From e30c00733a68a331d91c02066086ccd4daa4888f Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 24 Feb 2022 11:47:56 +0100 Subject: [PATCH 01/46] fix(linux): Don't start ibus-daemon multiple times This change adds a 1s sleep after restarting ibus before checking that it actually runs. Hopefully this will solve the problem. Since this bug is hard to reproduce, we also log a critical error for the other code path this could happen. Fixes #6237. --- linux/keyman-config/keyman_config/ibus_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux/keyman-config/keyman_config/ibus_util.py b/linux/keyman-config/keyman_config/ibus_util.py index 0ba5d773f3..0f26f7b2e2 100644 --- a/linux/keyman-config/keyman_config/ibus_util.py +++ b/linux/keyman-config/keyman_config/ibus_util.py @@ -91,7 +91,9 @@ def _verify_ibus_daemon(): ps = subprocess.run(('ps', '--user', user, '-o', 's=', '-o', 'cmd'), stdout=subprocess.PIPE).stdout if not re.search('^[^ZT] ibus-daemon .*--xim.*', ps.decode('utf-8'), re.MULTILINE): _start_ibus_daemon(realuser) - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as e: + # Log criticial error in order to track down #6237 + logging.critical('getting ibus-daemon failed (%s: %s)', type(e), e.args) _start_ibus_daemon(realuser) @@ -130,6 +132,7 @@ def restart_ibus(bus=None): except Exception as e: logging.warning("Failed to restart IBus") logging.warning(e) + time.sleep(1) # 1s _verify_ibus_daemon() From ed54dbead35b1d5d4c59e76f2047b32af3e8c444 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Jan 2022 10:18:54 +1000 Subject: [PATCH 02/46] fix(windows): null pointer checks --- .../developer/samples/imsample/IMSample.txt | 6 +- .../developer/samples/imsample/imsample.cpp | 120 +++++++++++------- 2 files changed, 76 insertions(+), 50 deletions(-) diff --git a/windows/src/developer/samples/imsample/IMSample.txt b/windows/src/developer/samples/imsample/IMSample.txt index 48c72872a2..eee1603f36 100644 --- a/windows/src/developer/samples/imsample/IMSample.txt +++ b/windows/src/developer/samples/imsample/IMSample.txt @@ -1,6 +1,8 @@ [Config] Font=Arial Unicode MS -Size=20 +Size=15 +gridx=30 +gridy=30 [Groups] IPA @@ -9,4 +11,4 @@ IPA IPA,"","a",U+00E6, "a", U+0251, U+0250, U+028C IPA,"","e",U+025B, U+025C, U+0259, "e", U+0258 IPA,"","o", "o", U+00F8, U+0254 -IPA,"","m", "m", "M", "###" +IPA,"","m", "m", "M", "###" \ No newline at end of file diff --git a/windows/src/developer/samples/imsample/imsample.cpp b/windows/src/developer/samples/imsample/imsample.cpp index 22f1a3c5a9..55ba965390 100644 --- a/windows/src/developer/samples/imsample/imsample.cpp +++ b/windows/src/developer/samples/imsample/imsample.cpp @@ -1,18 +1,18 @@ /* Name: imsample Copyright: Copyright (C) 2003-2017 SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 24 Oct 2012 Modified Date: 24 Oct 2012 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 24 Oct 2012 - mcdurdin - I3481 - V9.0 - Eliminate unsafe calls in C++ */ @@ -51,7 +51,7 @@ struct group struct keyboard { char name[128]; - + LOGFONT font; HFONT hFont; @@ -79,7 +79,7 @@ void CreateKeyboard(PSTR keyboardname); /************************************************************************************************************ - * DLL entry functions + * DLL entry functions ************************************************************************************************************/ BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -121,7 +121,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMInit(PSTR keyboardname) wc.lpszMenuName = NULL; wc.lpszClassName = "KM_IMSample"; if(!RegisterClass(&wc)) return FALSE; - + wc.lpfnWndProc = (WNDPROC) IMSampleChildWndProc; wc.lpszClassName = "KM_IMSampleChild"; if(!RegisterClass(&wc)) return FALSE; @@ -131,7 +131,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMInit(PSTR keyboardname) pt.x = ReadRegSetting("imsample x"); pt.y = ReadRegSetting("imsample y"); - hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, "KM_IMSample", "Keyman Sample IM", + hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, "KM_IMSample", "Keyman Sample IM", WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, pt.x, pt.y, 200, 120, 0, NULL, hinst, NULL); @@ -160,7 +160,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMReloadConfig(PSTR keyboardn } /************************************************************************************************************ - * IM Events + * IM Events ************************************************************************************************************/ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMActivate(PSTR keyboardname) @@ -295,7 +295,10 @@ void CalcScrollSize() RECT rect; if(!curkbd) { wz.cellcount = 0; return; } - + if (!curkbd->groups) { + wz.cellcount = 0; + return; + } GetClientRect(hwndChild, &rect); if(FIMWindowActive && currule) @@ -308,6 +311,7 @@ void CalcScrollSize() wz.cellcount = 0; int i; + for(i = 0; i < curkbd->groups[0].nrules; i++) { rule *r = &curkbd->groups[0].rules[i]; @@ -320,8 +324,8 @@ void CalcScrollSize() wz.visiblecolcount = (curkbd->gridx != 0 ? rect.right / curkbd->gridx : rect.right); wz.visiblerowcount = (curkbd->gridy != 0 ? rect.bottom / curkbd->gridy : rect.bottom); - wz.xi = (wz.cellcount-1) % wz.visiblecolcount; - wz.yi = (wz.cellcount-1) / wz.visiblecolcount; + wz.xi = (wz.visiblecolcount !=0 ) ? (wz.cellcount-1) % wz.visiblecolcount : 2; + wz.yi = (wz.visiblecolcount !=0 ) ? (wz.cellcount-1) / wz.visiblecolcount : 2; SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); @@ -359,17 +363,19 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L case WM_USER+200: CalcScrollSize(); InvalidateRect(hwndChild, NULL, TRUE); - + return 0; case WM_LBUTTONUP: if(!PrepIM()) return DefWindowProc(hwndChild, msg, wParam, lParam); if(!curkbd) return 0; - + if (!curkbd->groups) { + return 0; + } GetClientRect(hwndChild, &rect); pt = MAKEPOINTS(lParam); - + pt.x /= cx; pt.y /= cy; @@ -378,8 +384,8 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L if(!FIMWindowActive || !currule) { int i, j; for(i = 0, j = 0; i < curkbd->groups[0].nrules; i++) - if(curkbd->groups[0].rules[i].drawvalid) - { + if(curkbd->groups[0].rules[i].drawvalid) + { if(j == n) break; j++; } @@ -403,7 +409,7 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L case WM_VSCROLL: nPos = HIWORD(wParam); - if(nPos == 0 && LOWORD(wParam) != SB_THUMBTRACK && LOWORD(wParam) != SB_THUMBPOSITION) + if(nPos == 0 && LOWORD(wParam) != SB_THUMBTRACK && LOWORD(wParam) != SB_THUMBPOSITION) nPos = GetScrollPos(hwndChild, SB_VERT); switch(LOWORD(wParam)) { @@ -426,10 +432,19 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L return 0; case WM_PAINT: + if (!curkbd) { + return 0; + } + if (!curkbd->hFont) { + return 0; + } + if (!curkbd->groups) { + return 0; + } if(!PrepIM()) return DefWindowProc(hwndChild, msg, wParam, lParam); - + int vpos = GetScrollPos(hwndChild, SB_VERT) * curkbd->gridy; - + hDC = BeginPaint(hwndChild, &ps); GetClientRect(hwndChild, &rect); if(curkbd) @@ -460,12 +475,12 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L SelectObject(hDC, GetStockObject(SYSTEM_FONT)); TextOut(hDC, x * cx + 1, -vpos + y * cy+1, buf, 1); SelectObject(hDC, curkbd->hFont); - + SIZE sz2; GetTextExtentPoint32W(hDC, currule->outputs[i], (int)wcslen(currule->outputs[i]), &sz2); - - TextOutW(hDC, x * cx + (cx-sz2.cx)/2, -vpos + (y+1) * cy - sz2.cy - 2, + + TextOutW(hDC, x * cx + (cx-sz2.cx)/2, -vpos + (y+1) * cy - sz2.cy - 2, currule->outputs[i], (int)wcslen(currule->outputs[i])); if(++x >= wz.visiblecolcount) { x = 0; y++; } @@ -509,7 +524,10 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L BOOL FindRule(group *g, rule **rp, WCHAR KeyChar) { - WCHAR buf[48]; + if(!g){ + return FALSE; + } + WCHAR buf[48]; if(!(*KMGetContext)(buf, 48)) return FALSE; rule *r = g->rules; int buflen = (int)wcslen(buf); @@ -526,7 +544,7 @@ BOOL FindRule(group *g, rule **rp, WCHAR KeyChar) } BOOL PostKey(WCHAR KeyChar, WORD KeyStroke) -{ +{ if(KeyChar != 0) { WCHAR buf[2]; @@ -547,7 +565,10 @@ BOOL PostKey(WCHAR KeyChar, WORD KeyStroke) extern "C" BOOL __declspec(dllexport) WINAPI DFWindow(HWND hwndFocus, WORD KeyStroke, WCHAR KeyChar, DWORD shiftFlags) { if(!curkbd) return FALSE; - + if (!curkbd->groups) { + return FALSE; + } + if(!FindRule(&curkbd->groups[0], &currule, KeyChar)) { if(FIMWindowAlwaysVisible) @@ -566,6 +587,9 @@ extern "C" BOOL __declspec(dllexport) WINAPI DFText(HWND hwndFocus, WORD KeyStro { WCHAR buf[32]; if(!curkbd) return FALSE; + if (!curkbd->groups) { + return FALSE; + } if(!currule) { if(!FindRule(&curkbd->groups[0], &currule, KeyChar)) @@ -589,7 +613,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI DFText(HWND hwndFocus, WORD KeyStro else if(KeyChar >= '1' && KeyChar <= '9') { KeyChar -= '1'; - if(currule->outputs[KeyChar]) + if(currule->outputs[KeyChar]) { (*KMSetOutput)(currule->outputs[KeyChar], currule->outputlen); currule = NULL; @@ -615,7 +639,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI DF(HWND hwndFocus, WORD KeyStroke, /************************************************************************************************************ - * IM Configuration + * IM Configuration ************************************************************************************************************/ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMConfigure(PSTR keyboardname, HWND hwndParent) @@ -634,7 +658,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMConfigure(PSTR keyboardname case IDYES: WriteRegSetting("ShowIMWindowAlways", 1); break; - + case IDNO: WriteRegSetting("ShowIMWindowAlways", 0); break; @@ -657,7 +681,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMConfigure(PSTR keyboardname void WriteRegSetting(PSTR text, int value) { HKEY hkey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) { RegSetValueEx(hkey, text, 0, REG_DWORD, (PBYTE) &value, 4); @@ -668,7 +692,7 @@ void WriteRegSetting(PSTR text, int value) int ReadRegSetting(PSTR text) { HKEY hkey; - if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", + if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) { unsigned long value, sz = 4, tp = REG_DWORD; @@ -684,10 +708,10 @@ int ReadRegSetting(PSTR text) char *strtokquoted(char *str, char *token, char *quotes) { //slow-n-ugly but quick to write ;-) static char *buf = NULL; - if(!str) + if(!str) if(!buf) return NULL; else str = buf; - + char *q = str; if(!*q) return q; @@ -699,7 +723,7 @@ char *strtokquoted(char *str, char *token, char *quotes) if(!r) return NULL; // unterminated quotes r++; if(!strchr(token, *r)) return NULL; // close of quoted string does not culminate in token - if(*r != 0) + if(*r != 0) { *r++ = 0; while(*r != 0 && strchr(token, *r)) r++; @@ -825,7 +849,7 @@ BOOL LoadRules(PSTR KeyboardName) BOOL FGroups = FALSE, FRules = FALSE, FConfig = FALSE; char str[512]; int nkbi, lfpixelsy; - + UnloadRules(KeyboardName); // Free existing rule base for(nkbi = 0; nkbi < nkeyboards; nkbi++) @@ -845,7 +869,7 @@ BOOL LoadRules(PSTR KeyboardName) kbi->font.lfHeight = -MulDiv(10, lfpixelsy, 72); kbi->font.lfWidth = 0; - kbi->font.lfEscapement = 0; + kbi->font.lfEscapement = 0; kbi->font.lfOrientation = 0; kbi->font.lfWeight = FW_NORMAL; kbi->font.lfItalic = FALSE; @@ -859,7 +883,7 @@ BOOL LoadRules(PSTR KeyboardName) strcpy_s(kbi->font.lfFaceName, _countof(kbi->font.lfFaceName), "Arial"); // I3481 char drive[_MAX_DRIVE], dir[_MAX_DIR], buf[260]; - + if(!(*KMGetKeyboardPath)(KeyboardName, buf, 260)) return FALSE; _splitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); // I3481 _makepath_s(buf, _countof(buf), drive, dir, "imsample", ".txt"); // I3481 @@ -873,7 +897,7 @@ BOOL LoadRules(PSTR KeyboardName) if(strchr(str, '\n')) *strchr(str, '\n') = 0; if(str[0] == '#' || str[0] == 0) continue; - + if(str[0] == '[') { FConfig = FALSE; FGroups = FALSE; FRules = FALSE; @@ -886,10 +910,10 @@ BOOL LoadRules(PSTR KeyboardName) char *tokcontext = NULL; char *p = strtok_s(str, "= ", &tokcontext); if(!p) continue; // I3481 char *q = strtok_s(NULL, "\n", &tokcontext); if(!q) continue; // I3481 - if(!_stricmp(p, "font")) - { - strncpy_s(kbi->font.lfFaceName, _countof(kbi->font.lfFaceName), q, LF_FACESIZE-1); - kbi->font.lfFaceName[LF_FACESIZE-1] = 0; + if(!_stricmp(p, "font")) + { + strncpy_s(kbi->font.lfFaceName, _countof(kbi->font.lfFaceName), q, LF_FACESIZE-1); + kbi->font.lfFaceName[LF_FACESIZE-1] = 0; } else if(!_stricmp(p, "size")) { @@ -911,7 +935,7 @@ BOOL LoadRules(PSTR KeyboardName) delete kbi->groups; } kbi->groups = g2; - + kbi->groups[kbi->ngroups].rules = NULL; kbi->groups[kbi->ngroups].nrules = 0; strncpy_s(kbi->groups[kbi->ngroups].name, _countof(kbi->groups[kbi->ngroups].name), str, 31); // I3481 @@ -940,7 +964,7 @@ BOOL LoadRules(PSTR KeyboardName) } kbi->groups[i].rules = r2; } - + rule *r2 = &kbi->groups[i].rules[kbi->groups[i].nrules++]; r2->context = extstr(pcontext); @@ -963,7 +987,7 @@ BOOL LoadRules(PSTR KeyboardName) } fclose(fp); - kbi->hFont = CreateFontIndirect(&kbi->font); + kbi->hFont = CreateFontIndirect(&kbi->font); return TRUE; } From 50f8c7bf3f57b531ff0ff0d10026e68ef910cf9d Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 2 Feb 2022 10:20:25 +1000 Subject: [PATCH 03/46] fix(windows): address review comments imsample kbd Co-authored-by: Marc Durdin --- .../src/developer/samples/imsample/imsample.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/windows/src/developer/samples/imsample/imsample.cpp b/windows/src/developer/samples/imsample/imsample.cpp index 55ba965390..66b6615db0 100644 --- a/windows/src/developer/samples/imsample/imsample.cpp +++ b/windows/src/developer/samples/imsample/imsample.cpp @@ -432,16 +432,9 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L return 0; case WM_PAINT: - if (!curkbd) { - return 0; + if (!curkbd || !curkbd->hFont || !curkbd->groups || !PrepIM()) { + return DefWindowProc(hwndChild, msg, wParam, lParam); } - if (!curkbd->hFont) { - return 0; - } - if (!curkbd->groups) { - return 0; - } - if(!PrepIM()) return DefWindowProc(hwndChild, msg, wParam, lParam); int vpos = GetScrollPos(hwndChild, SB_VERT) * curkbd->gridy; @@ -524,7 +517,7 @@ LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, L BOOL FindRule(group *g, rule **rp, WCHAR KeyChar) { - if(!g){ + if (!g || !rp) { return FALSE; } WCHAR buf[48]; @@ -586,8 +579,7 @@ extern "C" BOOL __declspec(dllexport) WINAPI DFWindow(HWND hwndFocus, WORD KeySt extern "C" BOOL __declspec(dllexport) WINAPI DFText(HWND hwndFocus, WORD KeyStroke, WCHAR KeyChar, DWORD shiftFlags) { WCHAR buf[32]; - if(!curkbd) return FALSE; - if (!curkbd->groups) { + if (!curkbd || !curkbd->groups) { return FALSE; } if(!currule) From 272c1f0d1c4f6a0ea72599b793c9d0fd1cd6d494 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 8 Mar 2022 17:25:09 +1100 Subject: [PATCH 04/46] fix(web): subkey touch position after scroll Fixes #5964. It seems that the test for subkey position was incorrect when the document had been scrolled. Removing the test for `fixed` positioning resolves the issue. --- web/source/osk/oskKey.ts | 18 ------------------ web/testing/unminified.html | 4 ++++ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/web/source/osk/oskKey.ts b/web/source/osk/oskKey.ts index d156c07b27..0b71253890 100644 --- a/web/source/osk/oskKey.ts +++ b/web/source/osk/oskKey.ts @@ -509,26 +509,8 @@ namespace com.keyman.osk { let y = input.y; let btn = this.btn; - // These functions do not account for 'fixed' positioning. let x0 = dom.Utils.getAbsoluteX(btn); let y0 = dom.Utils.getAbsoluteY(btn); - - let isFixed = false; - let node: HTMLElement = btn; - while(node) { - if(getComputedStyle(node).position == 'fixed') { - isFixed = true; - break; - } else { - node = node.offsetParent as HTMLElement; - } - } - - if(isFixed) { - x0 += window.pageXOffset; - y0 += window.pageYOffset; - } - let x1 = x0 + btn.offsetWidth; let y1 = y0 + btn.offsetHeight; diff --git a/web/testing/unminified.html b/web/testing/unminified.html index 4f1a28c731..39818c3bc1 100644 --- a/web/testing/unminified.html +++ b/web/testing/unminified.html @@ -83,6 +83,10 @@

Return to testing home page

+ +
+

--End of Document--

+ + +

+ +

+

Mobile/Tablet Layout

+

Due to the size and number of keys, some characters are hidden in the long press. Press and hold on the key with a little dot on the top right to reveal and use them.

+

+ +

+ +

+ +

+ In this language, note that: +

(1) Only one tone mark can sit on a letter. So, diacritic stacking is not allowed. +

(2) Some tones are not to be marked in writing; they are not required. They are only used in primers and for beginners. +

(3) Some letters do not accept some accents. +

(4) Others do not accept accents at all. +

+Except for the optional accents which are not required, the keyboard will notify you when you inadvertently go against the spelling rules. +

+On mobile devices, tap the deadkey (⨷) then the given key to get the English letter in that position. +

+On desktop, if what you are doing does not support 'n̄' or does not render it well, then you can tap the BACKSLASH key after the 'n̄' to get 'ñ'. +

+The position of your BACKSLASH key depends on type of keyboard you are using. You can tell where your BACKSLASH key is by looking at the shape of the ENTER/RETURN key on your keyboard +

The three keyboard types and the respective position of the BACKSLASH keys are shown below: +

+ +

+ +

+ +

+Use this sentence to test your keyboard and character set: +

+mkpinyọn̄ kè evion̄ îben nchat balì ije bûu kire ǹnàan̄ iraka òsô mè ùkộ fiâm ikilap mudim m̀fọ̀tọ̀ shishini me èwê ozugbo +

+MKPINYỌN̄ KÈ EVION̄ ÎBEN NCHAT BALÌ IJE BÛU KIRE ǸNÀAN̄ IRAKA ÒSÔ MÈ ÙKỘ FIÂM IKILAP MUDIM M̀FỌ̀TỌ̀ SHISHINI ME ÈWÊ OZUGBO +

+Keyman ... type to the world in your language. +
+Obolo Chwerty ... ge inu me usem kwun̄ ria si ere geelek me linyọn̄. +

Onirọ-o! +

Itọn̄ ikup inyi Awaji! + + From 9f153ecc17e47b4983e5c4d6497788234375e633 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 10 Mar 2022 10:12:09 +1100 Subject: [PATCH 10/46] chore(common): cleanup sh global color variables Some of the global color variables in shellHelperFunctions.sh were a little dangerously named. This cleans that up and removes a couple of redundant functions from other locations. mac/bashHelperFunctions.sh should be removed and replaced with references to shellHelperFunctions.sh -- but I wanted to leave that for a separate branch. --- common/core/web/input-processor/test.sh | 2 +- .../one-stage-embedded-webworker/build.sh | 27 ++++++------------- .../two-stage-embedded-webworker/build.sh | 27 ++++++------------- ios/i18n-export.sh | 6 ++--- ios/kmbuild.sh | 4 +-- mac/bashHelperFunctions.sh | 2 ++ resources/shellHelperFunctions.sh | 26 +++++++++--------- web/bulk_rendering/build.sh | 19 +------------ web/unit_tests/test.sh | 2 +- 9 files changed, 39 insertions(+), 76 deletions(-) diff --git a/common/core/web/input-processor/test.sh b/common/core/web/input-processor/test.sh index d24fb3df27..7fdf884c27 100755 --- a/common/core/web/input-processor/test.sh +++ b/common/core/web/input-processor/test.sh @@ -75,5 +75,5 @@ if [ $FETCH_DEPS = true ]; then fi # Now we run our local tests. -echo "${TERM_HEADING}Running Input Processor test suite${NORMAL}" +echo_heading "Running Input Processor test suite" test-headless || fail "Input Processor tests failed!" diff --git a/common/predictive-text/testing/one-stage-embedded-webworker/build.sh b/common/predictive-text/testing/one-stage-embedded-webworker/build.sh index 64e1628d7e..f319ad2c4c 100644 --- a/common/predictive-text/testing/one-stage-embedded-webworker/build.sh +++ b/common/predictive-text/testing/one-stage-embedded-webworker/build.sh @@ -1,33 +1,22 @@ -#! /bin/bash +#!/usr/bin/env bash # # Compiles the Language Modeling Layer for common use in predictive text and autocorrective applications. # Designed for optimal compatibility with the Keyman Suite. # +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../../../resources/build/build-utils.sh" +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +## END STANDARD BUILD SCRIPT INCLUDE + display_usage ( ) { echo "build.sh [-clean]" echo echo " -clean to erase pre-existing build products before a re-build" } -# Fails the build if a specified file does not exist. -assert ( ) { - if ! [ -f $1 ]; then - fail "Build failed." - exit 1 - fi -} - -# Prints a nice, common error message. -fail ( ) { - FAILURE_MSG="$1" - if [[ "$FAILURE_MSG" == "" ]]; then - FAILURE_MSG="Unknown failure." - fi - echo "${ERROR_RED}$FAILURE_MSG${NORMAL}" - exit 1 -} - SOURCE="testing/one-stage-embedded-webworker" echo "Node.js + dependencies check" diff --git a/common/predictive-text/testing/two-stage-embedded-webworker/build.sh b/common/predictive-text/testing/two-stage-embedded-webworker/build.sh index 0e1c9eae4b..1a1c5eb347 100644 --- a/common/predictive-text/testing/two-stage-embedded-webworker/build.sh +++ b/common/predictive-text/testing/two-stage-embedded-webworker/build.sh @@ -1,33 +1,22 @@ -#! /bin/bash +#!/usr/bin/env bash # # Compiles the Language Modeling Layer for common use in predictive text and autocorrective applications. # Designed for optimal compatibility with the Keyman Suite. # +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../../../resources/build/build-utils.sh" +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +## END STANDARD BUILD SCRIPT INCLUDE + display_usage ( ) { echo "build.sh [-clean]" echo echo " -clean to erase pre-existing build products before a re-build" } -# Fails the build if a specified file does not exist. -assert ( ) { - if ! [ -f $1 ]; then - fail "Build failed." - exit 1 - fi -} - -# Prints a nice, common error message. -fail ( ) { - FAILURE_MSG="$1" - if [[ "$FAILURE_MSG" == "" ]]; then - FAILURE_MSG="Unknown failure." - fi - echo "${ERROR_RED}$FAILURE_MSG${NORMAL}" - exit 1 -} - SOURCE="testing/two-stage-embedded-webworker" COMPILED_WORKER="worker.js" diff --git a/ios/i18n-export.sh b/ios/i18n-export.sh index 11ce47d727..cac8637f1b 100755 --- a/ios/i18n-export.sh +++ b/ios/i18n-export.sh @@ -19,7 +19,7 @@ verify_on_mac #xcodebuild -exportLocalizations -project "engine/KMEI/KeymanEngine.xcodeproj" -#xcodebuild -exportLocalizations -project "keyman/Keyman/Keyman.xcodeproj" +#xcodebuild -exportLocalizations -project "keyman/Keyman/Keyman.xcodeproj" BASE_EXPORT_FOLDER="build/crowdin" START_DIRECTORY=`pwd` @@ -52,8 +52,8 @@ echo "" echo "---------------------------------------------" echo "iOS base i18n files have been exported." echo "Examine the contents of the folder at" -echo "${SUCCESS_GREEN}$KEYMAN_ROOT/ios/$BASE_EXPORT_FOLDER${NORMAL}" +echo "${COLOR_GREEN}$KEYMAN_ROOT/ios/$BASE_EXPORT_FOLDER${COLOR_RESET}" echo "and compare against the iOS entries within" -echo "${SUCCESS_GREEN}$KEYMAN_ROOT/crowdin.yml${NORMAL}" +echo "${COLOR_GREEN}$KEYMAN_ROOT/crowdin.yml${COLOR_RESET}" echo "---------------------------------------------" diff --git a/ios/kmbuild.sh b/ios/kmbuild.sh index fae76b90af..c7c71780c4 100755 --- a/ios/kmbuild.sh +++ b/ios/kmbuild.sh @@ -207,7 +207,7 @@ update_bundle ( ) { downloadKeyboardPackage "$DEFAULT_KBD_ID" "$base_dir/$BUNDLE_PATH/$DEFAULT_KBD_ID.kmp" downloadModelPackage "$DEFAULT_LM_ID" "$base_dir/$BUNDLE_PATH/$DEFAULT_LM_ID.model.kmp" - echo "${SUCCESS_GREEN}Packages successfully updated${NORMAL}" + echo "${COLOR_GREEN}Packages successfully updated${COLOR_RESET}" # If we aren't downloading resources, make sure copies of them already exist! fi @@ -317,7 +317,7 @@ if [ $DO_KEYMANAPP = true ]; then VERSION=$VERSION \ VERSION_WITH_TAG=$VERSION_WITH_TAG \ VERSION_ENVIRONMENT=$VERSION_ENVIRONMENT \ - UPLOAD_SENTRY=$UPLOAD_SENTRY + UPLOAD_SENTRY=$UPLOAD_SENTRY fi echo "" diff --git a/mac/bashHelperFunctions.sh b/mac/bashHelperFunctions.sh index 5374ab9ee1..1836fec621 100755 --- a/mac/bashHelperFunctions.sh +++ b/mac/bashHelperFunctions.sh @@ -1,5 +1,7 @@ #!/bin/sh +# TODO: deprecate and replace with shellHelperFunctions.sh. + # The following allows coloring of warning and error lines, but only works if there's a # terminal attached, so not on the build machine. if ! [[ "$TERM" == "" || "$TERM" == "dumb" ]]; then diff --git a/resources/shellHelperFunctions.sh b/resources/shellHelperFunctions.sh index 6fcbb2127f..1e95a6a7d4 100755 --- a/resources/shellHelperFunctions.sh +++ b/resources/shellHelperFunctions.sh @@ -85,21 +85,21 @@ get_platform_folder() { # The following allows coloring of warning and error lines, but only works if there's a # terminal attached, so not on the build machine. if [[ -n "$TERM" ]] && [[ "$TERM" != "dumb" ]] && [[ "$TERM" != "unknown" ]]; then - ERROR_RED=$(tput setaf 1) - SUCCESS_GREEN=$(tput setaf 2) - WARNING_YELLOW=$(tput setaf 3) - NORMAL=$(tput sgr0) - TERM_HEADING=$(tput setaf 4) + COLOR_RED=$(tput setaf 1) + COLOR_GREEN=$(tput setaf 2) + COLOR_BLUE=$(tput setaf 4) + COLOR_YELLOW=$(tput setaf 3) + COLOR_RESET=$(tput sgr0) else - ERROR_RED= - SUCCESS_GREEN= - WARNING_YELLOW= - NORMAL= - TERM_HEADING= + COLOR_RED= + COLOR_GREEN= + COLOR_BLUE= + COLOR_YELLOW= + COLOR_RESET= fi echo_heading() { - echo "${TERM_HEADING}$*${NORMAL}" + echo "${COLOR_BLUE}$*${COLOR_RESET}" } fail() { @@ -107,11 +107,11 @@ fail() { if [[ "$FAILURE_MSG" == "" ]]; then FAILURE_MSG="Unknown failure" fi - echo "${ERROR_RED}$FAILURE_MSG${NORMAL}" + echo "${COLOR_RED}$FAILURE_MSG${COLOR_RESET}" exit 1 } -warn() { echo "${WARNING_YELLOW}$*${NORMAL}"; } +warn() { echo "${COLOR_YELLOW}$*${COLOR_RESET}"; } displayInfo() { if [ "$QUIET" != true ]; then diff --git a/web/bulk_rendering/build.sh b/web/bulk_rendering/build.sh index 63d4d8c2aa..f63687ead9 100755 --- a/web/bulk_rendering/build.sh +++ b/web/bulk_rendering/build.sh @@ -1,5 +1,5 @@ #! /bin/bash -# +# # Compile the KeymanWeb bulk-renderer module for use with developing/running engine tests. ## START STANDARD BUILD SCRIPT INCLUDE @@ -9,23 +9,6 @@ THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BA . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" ## END STANDARD BUILD SCRIPT INCLUDE -# Fails the build if a specified file does not exist. -assert ( ) { - if ! [ -f $1 ]; then - fail "Build failed." - exit 1 - fi -} - -fail() { - FAILURE_MSG="$1" - if [[ "$FAILURE_MSG" == "" ]]; then - FAILURE_MSG="Unknown failure" - fi - echo "${ERROR_RED}$FAILURE_MSG${NORMAL}" - exit 1 -} - # Ensure the dependencies are downloaded. --no-optional should help block fsevents warnings. verify_npm_setup diff --git a/web/unit_tests/test.sh b/web/unit_tests/test.sh index 3666d7752f..9289fbaa85 100755 --- a/web/unit_tests/test.sh +++ b/web/unit_tests/test.sh @@ -135,7 +135,7 @@ pushd $WORKING_DIRECTORY/node_modules/@keymanapp/input-processor # Once done, now we run the integrated (KeymanWeb) tests. popd -echo "${TERM_HEADING}Running KeymanWeb integration test suite${NORMAL}" +echo_heading "Running KeymanWeb integration test suite" npm --no-color run modernizr -- -c unit_tests/modernizr.config.json -d unit_tests/modernizr.js npm --no-color run karma -- start $FLAGS $BROWSERS unit_tests/$CONFIG From 6e1e7e8e7e66690f562751335781c5a5658754aa Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 10 Mar 2022 10:26:15 +1100 Subject: [PATCH 11/46] chore: additional scripts --- common/core/web/input-processor/test.sh | 2 +- common/core/web/keyboard-processor/test.sh | 2 +- web/source/build.sh | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/core/web/input-processor/test.sh b/common/core/web/input-processor/test.sh index 7fdf884c27..a3c46c65cf 100755 --- a/common/core/web/input-processor/test.sh +++ b/common/core/web/input-processor/test.sh @@ -54,7 +54,7 @@ if [ $FETCH_DEPS = true ]; then fi # Ensures that the lexical model compiler has been built locally. -echo "${TERM_HEADING}Preparing Lexical Model Compiler for test use${NORMAL}" +echo_heading "Preparing Lexical Model Compiler for test use" pushd $WORKING_DIRECTORY/node_modules/@keymanapp/lexical-model-compiler npm run build popd diff --git a/common/core/web/keyboard-processor/test.sh b/common/core/web/keyboard-processor/test.sh index b66fb3cb56..ae82949fad 100755 --- a/common/core/web/keyboard-processor/test.sh +++ b/common/core/web/keyboard-processor/test.sh @@ -64,6 +64,6 @@ pushd "$KEYMAN_ROOT/common/core/web/tools/recorder/src" popd # Run headless (browserless) tests. -echo "${TERM_HEADING}Running Keyboard Processor test suite${NORMAL}" +echo_heading "Running Keyboard Processor test suite" test-headless || fail "Keyboard Processor tests failed!" diff --git a/web/source/build.sh b/web/source/build.sh index fc99ac4f6b..4bdabb0ba9 100755 --- a/web/source/build.sh +++ b/web/source/build.sh @@ -355,11 +355,11 @@ if [ $BUILD_CORE = true ]; then CORE_FLAGS="-skip-package-install" # Build the sentry-manager module - it's used in embedded contexts and on one testing page. - echo "${TERM_HEADING}Compiling KeymanWeb's sentry-manager module...${NORMAL}" + echo_heading "Compiling KeymanWeb's sentry-manager module..." pushd ../../common/core/web/tools/sentry-manager/src ./build.sh $CORE_FLAGS || fail "Failed to compile the sentry-manager module" popd - echo "${TERM_HEADING}sentry-manager module compiled successfully.${NORMAL}" + echo_heading "sentry-manager module compiled successfully." if [ $BUILD_LMLAYER = false ]; then CORE_FLAGS="$CORE_FLAGS -test" @@ -368,10 +368,10 @@ if [ $BUILD_CORE = true ]; then # Ensure that the Input Processor module compiles properly. cd ../../common/core/web/input-processor/src echo "" - echo "${TERM_HEADING}Compiling local KeymanWeb dependencies...${NORMAL}" + echo_heading "Compiling local KeymanWeb dependencies..." ./build.sh $CORE_FLAGS || fail "Failed to compile KeymanWeb dependencies" cd $WORKING_DIRECTORY - echo "${TERM_HEADING}Local KeymanWeb dependency compilations completed successfully.${NORMAL}" + echo_heading "Local KeymanWeb dependency compilations completed successfully." echo "" fi From d879c1e3f6e4ed2d08bccb0a62a6b068d8629ae4 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 9 Mar 2022 14:16:31 +1100 Subject: [PATCH 12/46] fix(web): caps state tracking for touch Selecting the new Caps Lock `caps` layer was not correctly setting the layer state in the key event to `caps`, which caused Caps Lock rules to fail to match. --- .../keyboard-processor/src/text/keyboardProcessor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts index f36bbb6124..dcd0d92e3b 100644 --- a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts +++ b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts @@ -184,9 +184,9 @@ namespace com.keyman.text { setSyntheticEventDefaults(Lkc: text.KeyEvent) { // Set the flags for the state keys. - Lkc.Lstates |= this.stateKeys['K_CAPS'] ? Codes.modifierCodes['CAPS'] : Codes.modifierCodes['NO_CAPS']; - Lkc.Lstates |= this.stateKeys['K_NUMLOCK'] ? Codes.modifierCodes['NUM_LOCK'] : Codes.modifierCodes['NO_NUM_LOCK']; - Lkc.Lstates |= this.stateKeys['K_SCROLL'] ? Codes.modifierCodes['SCROLL_LOCK'] : Codes.modifierCodes['NO_SCROLL_LOCK']; + Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['CAPS'] ? 0 : Codes.modifierCodes['NO_CAPS']; + Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['NUM_LOCK'] ? 0 : Codes.modifierCodes['NO_NUM_LOCK']; + Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['SCROLL_LOCK'] ? 0 : Codes.modifierCodes['NO_SCROLL_LOCK']; // Set LisVirtualKey to false to ensure that nomatch rule does fire for U_xxxx keys if(Lkc.kName && Lkc.kName.substr(0,2) == 'U_') { @@ -731,11 +731,11 @@ namespace com.keyman.text { } else if(KeyboardProcessor.isModifier(Levent)) { // For eventual integration - we bypass an OSK update for physical keystrokes when in touch mode. this.activeKeyboard.notify(Levent.Lcode, outputTarget, isKeyDown ? 1 : 0); - if(!Levent.device.touchable) { + if(!Levent.device.touchable) { return this._UpdateVKShift(Levent, Levent.Lcode-15, 1); // I2187 - } else { + } else { return true; - } + } } if(Levent.LmodifierChange) { From 9cabb7cd66a7ee681fe1ffbf00ba6edf983db565 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 10 Mar 2022 08:39:33 +1100 Subject: [PATCH 13/46] fix(web): add obolo_chwerty_6351 test keyboard --- .../keyboards/obolo_chwerty_6351/HISTORY.md | 36 + .../keyboards/obolo_chwerty_6351/LICENSE.md | 21 + .../keyboards/obolo_chwerty_6351/README.md | 37 + .../obolo_chwerty_6351.keyboard_info | 7 + .../obolo_chwerty_6351/obolo_chwerty_6351.kpj | 183 ++ .../source/obolo_chwerty_6351.css | 7 + .../source/obolo_chwerty_6351.ico | Bin 0 -> 1150 bytes .../obolo_chwerty_6351.keyman-touch-layout | 2053 +++++++++++++++++ .../source/obolo_chwerty_6351.kmn | 254 ++ .../source/obolo_chwerty_6351.kps | 121 + .../source/obolo_chwerty_6351.kvks | 114 + .../obolo_chwerty_6351/source/readme.htm | 29 + .../source/welcome/chwerty_default.png | Bin 0 -> 21265 bytes .../source/welcome/chwerty_keycombi.png | Bin 0 -> 24345 bytes .../source/welcome/chwerty_mobi_alt.png | Bin 0 -> 28130 bytes .../source/welcome/chwerty_mobi_default.png | Bin 0 -> 26988 bytes .../source/welcome/chwerty_mobi_shift.png | Bin 0 -> 29675 bytes .../source/welcome/chwerty_shift.png | Bin 0 -> 23725 bytes .../source/welcome/chwertyftkey1.png | Bin 0 -> 8096 bytes .../source/welcome/chwertyftkey2.png | Bin 0 -> 8306 bytes .../source/welcome/chwertyftkey3.png | Bin 0 -> 8323 bytes .../source/welcome/welcome.htm | 97 + 22 files changed, 2959 insertions(+) create mode 100644 common/test/keyboards/obolo_chwerty_6351/HISTORY.md create mode 100644 common/test/keyboards/obolo_chwerty_6351/LICENSE.md create mode 100644 common/test/keyboards/obolo_chwerty_6351/README.md create mode 100644 common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.keyboard_info create mode 100644 common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.kpj create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.css create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.ico create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.keyman-touch-layout create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kmn create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kps create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kvks create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/readme.htm create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_default.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_keycombi.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_alt.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_default.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_shift.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_shift.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey1.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey2.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey3.png create mode 100644 common/test/keyboards/obolo_chwerty_6351/source/welcome/welcome.htm diff --git a/common/test/keyboards/obolo_chwerty_6351/HISTORY.md b/common/test/keyboards/obolo_chwerty_6351/HISTORY.md new file mode 100644 index 0000000000..e4b8b51ee0 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/HISTORY.md @@ -0,0 +1,36 @@ +Obolo Chwerty Keyboard Change History +==================== + +1.2.1 (2021-11-23) +---------------- +* Removed accent key from numbers row on default layer, and from symbols row on shift layer. + +1.2.0 (2021-07-05) +---------------- +* Updated keycap for key 6 to match output on mobile shift layer, and added longpress for ^ +* Activated spacebar on layer alt for mobile/tablet layout +* Updated documentation +* Miscellaneous minor updates + +1.1.2 (2021-02-04) +---------------- +* Updated output for keys CH and SH on SHIFT layer to match key cap on touchscreen and desktop. +* Resolved capslock issue for keys CH, SH, Ọ and N̄ on desktop. +* Added long press on touchscreen for frequently used accented letters. +* Added the Naira sign (₦) and Ñ (an alternative where software cannot render N̄ well, though Ñ is not part of the Obolo orthography.) + +1.1.1 (2020-10-27) +---------------- +* Increment version number to force recompile of touch layout + +1.1 (2020-07-07) +---------------- +* Moved the high tone (which is not required, except in primers) to long press on low tone button (for touchscreen). +* Changed backspace behavior for ch, sh, n̄. +* Added long press for Q, H, X and C keys on touchscreen. +* Added hyphen-dash (a frequently used mark) to default and shift layers for touchscreen. +* Fixed typo and omissions in documentation. + +1.0 (2019-07-20) +---------------- +* Created by Rogers Katelem Edeh diff --git a/common/test/keyboards/obolo_chwerty_6351/LICENSE.md b/common/test/keyboards/obolo_chwerty_6351/LICENSE.md new file mode 100644 index 0000000000..eee2ba508b --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +© 2019 - 2021 Rogers Katelem Edeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/common/test/keyboards/obolo_chwerty_6351/README.md b/common/test/keyboards/obolo_chwerty_6351/README.md new file mode 100644 index 0000000000..2c5fe9b38d --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/README.md @@ -0,0 +1,37 @@ +Obolo Chwerty keyboard +============== + +© 2019 - 2021 Rogers Katelem Edeh + +Version 1.2.0 + +Description +----------- + +NOTE: This keyboard has been modified from the original for the purposes of testing https://github.com/keymanapp/keyman/issues/6351. It is not intended to be used for general purposes, and is not the final release version. Changes made: + +* NCAPS mismatches have been resolved +* Files renamed +* Font and PHP help have been removed (reduce distribution size) + +Obolo Chwerty Keyboard is a keyboard layout for the Obolo language of Nigeria. This layout covers the need of every dialect in that language. +On this keyboard, accents are typed after the base letters. So, to type Obolo language, simply tap the given latters and tap the appropriate accent key to place the accent on the letter. + +Links +----- +https://keyman.com/keyboards/obolo_chwerty + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.keyboard_info b/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.keyboard_info new file mode 100644 index 0000000000..1513b8bb47 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.keyboard_info @@ -0,0 +1,7 @@ +{ + "license": "mit", + "languages": [ + "ann-Latn" + ], + "description": "Obolo Chwerty Keyboard: A keyboard layout for the Obolo language of Nigeria. It covers the need of every dialect in that language" +} diff --git a/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.kpj b/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.kpj new file mode 100644 index 0000000000..7f076c964a --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/obolo_chwerty_6351.kpj @@ -0,0 +1,183 @@ + + + + $PROJECTPATH\build + True + True + True + keyboard + + + + id_e2041c991cdc20c570b342a5803447b0 + obolo_chwerty_6351.kmn + source\obolo_chwerty_6351.kmn + 1.2.1 + .kmn +

+ Obolo Chwerty + © 2019-2022 Rogers Katelem Edeh + A keyboard layout (chwerty) for the Obolo language of Nigeria. The keyboard covers the need of every dialect in that language. +
+ + + id_4ed7acb803d5177bff445780f774fdb3 + obolo_chwerty_6351.kps + source\obolo_chwerty_6351.kps + + .kps +
+ Obolo Chwerty + © 2019-2022 Rogers Katelem Edeh +
+
+ + id_ede98e4633e239f933cbfd1f4e1b766c + HISTORY.md + HISTORY.md + + .md + + + id_53e892b8b41cc4caece1cfd5ef21d6e7 + LICENSE.md + LICENSE.md + + .md + + + id_0730bb7c2e8f9ea2438b52e419dd86c9 + README.md + README.md + + .md + + + id_fa9ac62e52c7671ac61602e3583305fd + obolo_chwerty_6351.keyboard_info + obolo_chwerty_6351.keyboard_info + + .keyboard_info + + + id_ef2a383b75a0364689701ecbf2f6fefa + obolo_chwerty_6351.ico + source\obolo_chwerty_6351.ico + + .ico + id_e2041c991cdc20c570b342a5803447b0 + + + id_fa2b1b4a5977c1283d061d23611709ef + obolo_chwerty_6351.kvk + source\..\build\obolo_chwerty_6351.kvk + + .kvk + id_4ed7acb803d5177bff445780f774fdb3 + + + id_13adcc1b6b8e23edd35cfc6ab7c245b0 + obolo_chwerty_6351.kmx + source\..\build\obolo_chwerty_6351.kmx + + .kmx + id_4ed7acb803d5177bff445780f774fdb3 + + + id_3ec4dad3d83c69fc4b33eb86d401d8cb + obolo_chwerty_6351.js + source\..\build\obolo_chwerty_6351.js + + .js + id_4ed7acb803d5177bff445780f774fdb3 + + + id_f6212220adf6c5eb0ae25c33cb973c64 + chwerty_default.png + source\welcome\chwerty_default.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_cd62e578000692c9966c069950904d06 + chwerty_keycombi.png + source\welcome\chwerty_keycombi.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_2d29737f21e65a75ca98a9c3ab1f4a6f + chwerty_mobi_alt.png + source\welcome\chwerty_mobi_alt.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_2d856489cc6083c4b74a1b8c2b528785 + chwerty_mobi_default.png + source\welcome\chwerty_mobi_default.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_ee5bdb44f34cd08e1c6012f91790c302 + chwerty_mobi_shift.png + source\welcome\chwerty_mobi_shift.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_743e9cd02f1d4004a5320b9faa355587 + chwerty_shift.png + source\welcome\chwerty_shift.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_a81a3f903e8ce052259e09e4a6fbabb0 + chwertyftkey1.png + source\welcome\chwertyftkey1.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_cb8167846a4ac07edd78e5a39a7cc587 + chwertyftkey2.png + source\welcome\chwertyftkey2.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_7325a11eaf4f66357aa7185056091802 + chwertyftkey3.png + source\welcome\chwertyftkey3.png + + .png + id_4ed7acb803d5177bff445780f774fdb3 + + + id_724e5b4c63f10bc0abf7077f7c3172fc + welcome.htm + source\welcome\welcome.htm + + .htm + id_4ed7acb803d5177bff445780f774fdb3 + + + id_8da344c4cea6f467013357fe099006f5 + readme.htm + source\readme.htm + + .htm + id_4ed7acb803d5177bff445780f774fdb3 + + + diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.css b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.css new file mode 100644 index 0000000000..c07f696e50 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.css @@ -0,0 +1,7 @@ +/* tone keys colour */ +.android .kmw-keyboard-obolo_chwerty_6351 #default-T_GRV {color: #02ff02;} +.android .kmw-keyboard-obolo_chwerty_6351 #default-T_CCM {color: #02ff02;} +.android .kmw-keyboard-obolo_chwerty_6351 #shift-T_GRV {color: #02ff02;} +.android .kmw-keyboard-obolo_chwerty_6351 #shift-T_CCM {color: #02ff02;} +.android .kmw-keyboard-obolo_chwerty_6351 #caps-T_GRV {color: #02ff02;} +.android .kmw-keyboard-obolo_chwerty_6351 #caps-T_CCM {color: #02ff02;} diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.ico b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.ico new file mode 100644 index 0000000000000000000000000000000000000000..4d329aaf901d36929e3676852741696ec5bf5053 GIT binary patch literal 1150 zcmb_ZK@Pwm2*YF#@U*kX-TjlG7;8jJO60M8$+)xo~=+uC_s4D)#&^E>l=C9?kthPBke{8S|GZu|hs C`2b%4 literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.keyman-touch-layout b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.keyman-touch-layout new file mode 100644 index 0000000000..c9e7ea336e --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.keyman-touch-layout @@ -0,0 +1,2053 @@ +{ + "tablet": { + "font": "Tahoma", + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1", + "width": "111", + "sk": [ + { + "text": "¹", + "id": "U_00B9" + }, + { + "text": "₁", + "id": "U_2081" + } + ] + }, + { + "id": "K_2", + "text": "2", + "width": "111", + "sk": [ + { + "text": "²", + "id": "U_00B2" + }, + { + "id": "U_2082" + } + ] + }, + { + "id": "K_3", + "text": "3", + "width": "111", + "sk": [ + { + "text": "³", + "id": "U_00B3" + }, + { + "id": "U_2083" + } + ] + }, + { + "id": "K_4", + "text": "4", + "width": "111", + "sk": [ + { + "text": "⁴", + "id": "U_2074" + }, + { + "text": "₄", + "id": "U_2084" + } + ] + }, + { + "id": "K_5", + "text": "5", + "width": "111", + "sk": [ + { + "text": "⁵", + "id": "U_2075" + }, + { + "id": "U_2085" + } + ] + }, + { + "id": "K_6", + "text": "6", + "width": "111", + "sk": [ + { + "text": "⁶", + "id": "U_2076" + }, + { + "id": "U_2086" + } + ] + }, + { + "id": "K_7", + "text": "7", + "width": "111", + "sk": [ + { + "text": "⁷", + "id": "U_2077" + }, + { + "id": "U_2087" + } + ] + }, + { + "id": "K_8", + "text": "8", + "width": "111", + "sk": [ + { + "text": "⁸", + "id": "U_2078" + }, + { + "text": "₈", + "id": "U_2088" + } + ] + }, + { + "id": "K_9", + "text": "9", + "width": "111", + "sk": [ + { + "text": "⁹", + "id": "U_2079" + }, + { + "id": "U_2089" + } + ] + }, + { + "id": "K_0", + "text": "0", + "width": "111", + "sk": [ + { + "text": "⁰", + "id": "U_2070" + }, + { + "id": "U_2080" + } + ] + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "T_Q", + "text": "ch", + "pad": "", + "width": "", + "sk": [ + { + "text": "q", + "id": "U_0071" + } + ] + }, + { + "id": "K_W", + "text": "w" + }, + { + "id": "K_E", + "text": "e", + "sk": [ + { + "text": "è", + "id": "U_00E8" + }, + { + "text": "ê", + "id": "U_00EA" + } + ] + }, + { + "id": "K_R", + "text": "r" + }, + { + "id": "K_T", + "text": "t" + }, + { + "id": "K_Y", + "text": "y" + }, + { + "id": "K_U", + "text": "u", + "sk": [ + { + "text": "ù", + "id": "U_00F9" + }, + { + "text": "û", + "id": "U_00FB" + } + ] + }, + { + "id": "K_I", + "text": "i", + "sk": [ + { + "text": "ì", + "id": "U_00EC" + }, + { + "text": "î", + "id": "U_00EE" + } + ] + }, + { + "id": "K_O", + "text": "o", + "sk": [ + { + "text": "ò", + "id": "U_00F2" + }, + { + "text": "ô", + "id": "U_00F4" + } + ] + }, + { + "id": "K_P", + "text": "p" + }, + { + "id": "T_GRV", + "text": "ˋ", + "sk": [ + { + "text": "´", + "id": "T_ACU" + } + ] + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_A", + "text": "a", + "pad": "70", + "sk": [ + { + "text": "à", + "id": "U_00E0" + }, + { + "text": "â", + "id": "U_00E2" + } + ] + }, + { + "id": "K_S", + "text": "s" + }, + { + "id": "K_D", + "text": "d" + }, + { + "id": "K_F", + "text": "f" + }, + { + "id": "K_G", + "text": "g" + }, + { + "id": "T_H", + "text": "sh", + "sk": [ + { + "text": "h", + "id": "U_0068" + }, + { + "text": "ṣ", + "id": "U_1E63" + } + ] + }, + { + "id": "K_J", + "text": "j" + }, + { + "id": "K_K", + "text": "k" + }, + { + "id": "K_L", + "text": "l" + }, + { + "id": "T_CCM", + "text": "ˆ", + "sk": [ + { + "text": "ˇ", + "id": "T_CRN" + } + ] + }, + { + "id": "T_SPA", + "text": "", + "width": "40", + "sp": "10" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "pad": "50", + "width": "120", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_Z", + "text": "z" + }, + { + "id": "T_X", + "text": "ọ", + "sk": [ + { + "text": "ọ̀", + "id": "U_1ECD_0300" + }, + { + "text": "ộ", + "id": "U_1ED9" + }, + { + "text": "x", + "id": "U_0078" + } + ] + }, + { + "id": "T_C", + "text": "n̄", + "sk": [ + { + "text": "ñ", + "id": "U_00F1" + }, + { + "text": "c", + "id": "U_0063" + } + ] + }, + { + "id": "K_V", + "text": "v" + }, + { + "id": "K_B", + "text": "b" + }, + { + "id": "K_N", + "text": "n", + "sk": [ + { + "text": "ǹ", + "id": "U_01F9" + } + ] + }, + { + "id": "K_M", + "text": "m", + "sk": [ + { + "text": "m̀", + "id": "U_006D_0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "text": "!", + "id": "U_0021" + }, + { + "text": "/", + "id": "U_002F" + }, + { + "text": "'", + "id": "U_0027" + }, + { + "text": "\"", + "id": "U_0022" + }, + { + "text": "(", + "id": "U_0028" + }, + { + "text": ")", + "id": "U_0029" + }, + { + "text": "?", + "id": "U_003F" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "120", + "sp": "1" + }, + { + "id": "T_SPB", + "text": "", + "width": "20", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_ALT", + "text": "*Symbol*", + "width": "120", + "sp": "1", + "nextlayer": "alt" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "K_COMMA", + "text": ",", + "sk": [ + { + "text": ";", + "id": "U_003B" + } + ] + }, + { + "id": "K_SPACE", + "text": "", + "width": "520", + "sp": "0" + }, + { + "id": "K_PERIOD", + "text": ".", + "sk": [ + { + "text": ":", + "id": "U_003A" + } + ] + }, + { + "id": "T_ENG", + "text": "⨷", + "sp": "1", + "sk": [ + { + "text": "–", + "id": "U_2013" + }, + { + "text": "—", + "id": "U_2014" + }, + { + "text": "_", + "id": "U_005F" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "120", + "sp": "1" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "!", + "width": "111" + }, + { + "id": "K_2", + "text": "@", + "width": "111" + }, + { + "id": "K_3", + "text": "#", + "width": "111" + }, + { + "id": "K_4", + "text": "$", + "width": "111" + }, + { + "id": "K_5", + "text": "%", + "width": "111", + "sk": [ + { + "text": "‰", + "id": "U_2030" + }, + { + "text": "‱", + "id": "U_2031" + } + ] + }, + { + "id": "U_20A6", + "text": "₦", + "width": "111", + "sk": [ + { + "text": "^", + "id": "U_005E" + } + ] + }, + { + "id": "K_7", + "text": "&", + "width": "111" + }, + { + "id": "K_8", + "text": "*", + "width": "111" + }, + { + "id": "K_9", + "text": "(", + "width": "111" + }, + { + "id": "K_0", + "text": ")", + "width": "111" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "T_Q", + "text": "Ch", + "pad": "", + "sk": [ + { + "text": "Q", + "id": "U_0051" + } + ] + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E", + "sk": [ + { + "text": "È", + "id": "U_00C8" + }, + { + "text": "Ê", + "id": "U_00CA" + } + ] + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U", + "sk": [ + { + "text": "Ù", + "id": "U_00D9" + }, + { + "text": "Û", + "id": "U_00DB" + } + ] + }, + { + "id": "K_I", + "text": "I", + "sk": [ + { + "text": "Ì", + "id": "U_00CC" + }, + { + "text": "Î", + "id": "U_00CE" + } + ] + }, + { + "id": "K_O", + "text": "O", + "sk": [ + { + "text": "Ò", + "id": "U_00D2" + }, + { + "text": "Ô", + "id": "U_00D4" + } + ] + }, + { + "id": "K_P", + "text": "P" + }, + { + "id": "T_GRV", + "text": "`", + "sk": [ + { + "text": "´", + "id": "T_ACU" + } + ] + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_A", + "text": "A", + "pad": "70", + "sk": [ + { + "text": "À", + "id": "U_00C0" + }, + { + "text": "Â", + "id": "U_00C2" + } + ] + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "T_H", + "text": "Sh", + "sk": [ + { + "text": "H", + "id": "U_0048" + }, + { + "text": "Ṣ", + "id": "U_1E62" + } + ] + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "id": "T_CCM", + "text": "ˆ", + "sk": [ + { + "text": "ˇ", + "id": "T_CRN" + } + ] + }, + { + "id": "T_SPC", + "text": "", + "width": "40", + "sp": "10" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "pad": "50", + "width": "120", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "T_X", + "text": "Ọ", + "sk": [ + { + "text": "Ọ̀", + "id": "U_1ECC_0300" + }, + { + "text": "Ộ", + "id": "U_1ED8" + }, + { + "text": "X", + "id": "U_0058" + } + ] + }, + { + "id": "T_C", + "text": "N̄", + "sk": [ + { + "text": "Ñ", + "id": "U_00D1" + }, + { + "text": "C", + "id": "U_0043" + } + ] + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N", + "sk": [ + { + "text": "Ǹ", + "id": "U_01F8" + } + ] + }, + { + "id": "K_M", + "text": "M", + "sk": [ + { + "text": "M̀", + "id": "U_004D_0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "text": "!", + "id": "U_0021" + }, + { + "text": "/", + "id": "U_002F" + }, + { + "text": "'", + "id": "U_0027" + }, + { + "text": "\"", + "id": "U_0022" + }, + { + "text": "(", + "id": "U_0028" + }, + { + "text": ")", + "id": "U_0029" + }, + { + "text": "?", + "id": "U_003F" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "120", + "sp": "1" + }, + { + "id": "T_SPD", + "text": "", + "width": "20", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_ALT", + "text": "*Symbol*", + "width": "120", + "sp": "1", + "nextlayer": "alt" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "U_002C", + "text": ",", + "width": "", + "sk": [ + { + "text": ";", + "id": "U_003B" + } + ] + }, + { + "id": "K_SPACE", + "text": "", + "width": "520", + "sp": "0" + }, + { + "id": "U_002E", + "text": ".", + "sk": [ + { + "text": ":", + "id": "U_003A" + } + ] + }, + { + "id": "T_ENG", + "text": "⨷", + "sp": "1", + "sk": [ + { + "text": "–", + "id": "U_2013" + }, + { + "text": "—", + "id": "U_2014" + }, + { + "text": "_", + "id": "U_005F" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "120", + "sp": "1" + } + ] + } + ] + }, + { + "id": "alt", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "¹", + "id": "U_00B9" + }, + { + "text": "₁", + "id": "U_2081" + } + ] + }, + { + "id": "K_2", + "text": "2", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "²", + "id": "U_00B2" + }, + { + "text": "₂", + "id": "U_2082" + } + ] + }, + { + "id": "K_3", + "text": "3", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "³", + "id": "U_00B3" + }, + { + "text": "₃", + "id": "U_2083" + } + ] + }, + { + "id": "K_4", + "text": "4", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁴", + "id": "U_2074" + }, + { + "text": "₄", + "id": "U_2084" + } + ] + }, + { + "id": "K_5", + "text": "5", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁵", + "id": "U_2075" + }, + { + "text": "₅", + "id": "U_2085" + } + ] + }, + { + "id": "K_6", + "text": "6", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁶", + "id": "U_2076" + }, + { + "text": "₆", + "id": "U_2086" + } + ] + }, + { + "id": "K_7", + "text": "7", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁷", + "id": "U_2077" + }, + { + "text": "₇", + "id": "U_2087" + } + ] + }, + { + "id": "K_8", + "text": "8", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁸", + "id": "U_2078" + }, + { + "text": "₈", + "id": "U_2088" + } + ] + }, + { + "id": "K_9", + "text": "9", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁹", + "id": "U_2079" + }, + { + "text": "₉", + "id": "U_2089" + } + ] + }, + { + "id": "K_0", + "text": "0", + "width": "111", + "layer": "default", + "sk": [ + { + "text": "⁰", + "id": "U_2070" + }, + { + "text": "₀", + "id": "U_2080" + } + ] + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "U_002B", + "text": "+", + "pad": "", + "sk": [ + { + "text": "±", + "id": "U_00B1" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "text": "∓", + "id": "U_2213" + } + ] + }, + { + "id": "U_00D7", + "text": "×" + }, + { + "id": "U_00F7", + "text": "÷" + }, + { + "id": "U_2236", + "text": "∶", + "sk": [ + { + "text": "·", + "id": "U_00B7" + }, + { + "text": "∴", + "id": "U_2234" + }, + { + "text": "∵", + "id": "U_2235" + } + ] + }, + { + "id": "U_221A", + "text": "√", + "sk": [ + { + "text": "∛", + "id": "U_221B" + }, + { + "text": "∜", + "id": "U_221C" + } + ] + }, + { + "id": "U_005E", + "text": "^" + }, + { + "id": "U_003D", + "text": "=", + "sk": [ + { + "text": "≠", + "id": "U_2260" + }, + { + "text": "≈", + "id": "U_2248" + }, + { + "text": "≡", + "id": "U_2261" + } + ] + }, + { + "id": "U_007E", + "text": "~" + }, + { + "id": "U_203D", + "text": "‽", + "width": "", + "sk": [ + { + "text": "¡", + "id": "U_00A1" + } + ] + }, + { + "id": "U_2713", + "text": "✓", + "sk": [ + { + "text": "Δ", + "id": "U_0394" + }, + { + "text": "✗", + "id": "U_2717" + }, + { + "text": "⛯", + "id": "U_26EF" + }, + { + "text": "⛭", + "id": "U_26ED" + } + ] + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "U_007B", + "text": "{", + "pad": "" + }, + { + "id": "U_00AB", + "text": "«" + }, + { + "id": "U_003C", + "text": "<", + "sk": [ + { + "text": "≪", + "id": "U_226A" + }, + { + "text": "≤", + "id": "U_2264" + } + ] + }, + { + "id": "U_005B", + "text": "[" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_007C", + "text": "|" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_005D", + "text": "]" + }, + { + "id": "U_003E", + "text": ">", + "sk": [ + { + "text": "≫", + "id": "U_226B" + }, + { + "text": "≥", + "id": "U_2265" + } + ] + }, + { + "id": "U_00BB", + "text": "»" + }, + { + "id": "U_007D", + "text": "}" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "pad": "50", + "width": "120", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "U_221E", + "text": "∞", + "sk": [ + { + "text": "∂", + "id": "U_2202" + } + ] + }, + { + "id": "U_222B", + "text": "∫", + "sk": [ + { + "text": "ẋ", + "id": "U_1E8B" + }, + { + "text": "ẍ", + "id": "U_1E8D" + }, + { + "text": "ẏ", + "id": "U_1E8F" + }, + { + "text": "ӱ", + "id": "U_04F1" + } + ] + }, + { + "id": "U_00B0", + "text": "°", + "sk": [ + { + "text": "℃", + "id": "U_2103" + }, + { + "text": "℉", + "id": "U_2109" + } + ] + }, + { + "id": "U_03C0", + "text": "π" + }, + { + "id": "U_03B8", + "text": "θ" + }, + { + "id": "U_33D1", + "text": "㏑", + "sk": [ + { + "text": "㏒", + "id": "U_33D2" + } + ] + }, + { + "id": "U_00A9", + "text": "©", + "sk": [ + { + "text": "®", + "id": "U_00AE" + }, + { + "text": "℗", + "id": "U_2117" + }, + { + "text": "🛈", + "id": "U_1F6C8" + }, + { + "text": "™", + "id": "U_2122" + }, + { + "text": "℅", + "id": "U_2105" + } + ] + }, + { + "id": "U_002F", + "text": "/", + "sk": [ + { + "text": "\\", + "id": "U_005C" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "120", + "sp": "1" + }, + { + "id": "T_SPF", + "text": "", + "width": "20", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_ALT", + "text": "*abc*", + "width": "120", + "sp": "1", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "U_00A7", + "text": "§", + "sk": [ + { + "text": "₍", + "id": "U_208D" + }, + { + "text": "ₓ", + "id": "U_2093" + }, + { + "text": "₊", + "id": "U_208A" + }, + { + "text": "₋", + "id": "U_208B" + }, + { + "text": "₎", + "id": "U_208E" + }, + { + "text": "₌", + "id": "U_208C" + } + ] + }, + { + "id": "K_SPACE", + "text": "", + "width": "520", + "sp": "0", + "layer": "default" + }, + { + "id": "U_00B6", + "text": "¶", + "sk": [ + { + "text": "⁽", + "id": "U_207D" + }, + { + "text": "ⁿ", + "id": "U_207F" + }, + { + "text": "⁺", + "id": "U_207A" + }, + { + "text": "⁻", + "id": "U_207B" + }, + { + "text": "⁾", + "id": "U_207E" + }, + { + "text": "⁼", + "id": "U_207C" + } + ] + }, + { + "id": "U_03A9", + "text": "Ω", + "sp": "1", + "sk": [ + { + "text": "♚", + "id": "U_265A" + }, + { + "text": "♔", + "id": "U_2654" + }, + { + "text": "♛", + "id": "U_265B" + }, + { + "text": "♕", + "id": "U_2655" + }, + { + "text": "♝", + "id": "U_265D" + }, + { + "text": "♗", + "id": "U_2657" + }, + { + "text": "♜", + "id": "U_265C" + }, + { + "text": "♖", + "id": "U_2656" + }, + { + "text": "♞", + "id": "U_265E" + }, + { + "text": "♘", + "id": "U_2658" + }, + { + "text": "♟", + "id": "U_265F" + }, + { + "text": "♙", + "id": "U_2659" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "120", + "sp": "1" + } + ] + } + ] + }, + { + "id": "caps", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1", + "width": "111" + }, + { + "id": "K_2", + "text": "2", + "width": "111" + }, + { + "id": "K_3", + "text": "3", + "width": "111" + }, + { + "id": "K_4", + "text": "4", + "width": "111" + }, + { + "id": "K_5", + "text": "5", + "width": "111" + }, + { + "id": "K_6", + "text": "6", + "width": "111" + }, + { + "id": "K_7", + "text": "7", + "width": "111" + }, + { + "id": "K_8", + "text": "8", + "width": "111" + }, + { + "id": "K_9", + "text": "9", + "width": "111" + }, + { + "id": "K_0", + "text": "0", + "width": "111" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "T_Q", + "text": "CH", + "pad": "", + "sk": [ + { + "text": "Q", + "id": "U_0051" + } + ] + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E", + "sk": [ + { + "text": "È", + "id": "U_00C8" + }, + { + "text": "Ê", + "id": "U_00CA" + } + ] + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U", + "sk": [ + { + "text": "Ù", + "id": "U_00D9" + }, + { + "text": "Û", + "id": "U_00DB" + } + ] + }, + { + "id": "K_I", + "text": "I", + "sk": [ + { + "text": "Ì", + "id": "U_00CC" + }, + { + "text": "Î", + "id": "U_00CE" + } + ] + }, + { + "id": "K_O", + "text": "O", + "sk": [ + { + "text": "Ò", + "id": "U_00D2" + }, + { + "text": "Ô", + "id": "U_00D4" + } + ] + }, + { + "id": "K_P", + "text": "P" + }, + { + "id": "T_GRV", + "text": "`", + "sk": [ + { + "text": "´", + "id": "T_ACU" + } + ] + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_A", + "text": "A", + "pad": "70", + "sk": [ + { + "text": "À", + "id": "U_00C0" + }, + { + "text": "Â", + "id": "U_00C2" + } + ] + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "T_H", + "text": "SH", + "sk": [ + { + "text": "H", + "id": "U_0048" + }, + { + "text": "Ṣ", + "id": "U_1E62" + } + ] + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "id": "T_CCM", + "text": "ˆ", + "sk": [ + { + "text": "ˇ", + "id": "T_CRN" + } + ] + }, + { + "id": "T_SPC", + "text": "", + "width": "40", + "sp": "10" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "pad": "50", + "width": "120", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "T_X", + "text": "Ọ", + "sk": [ + { + "text": "Ọ̀", + "id": "U_1ECC_0300" + }, + { + "text": "Ộ", + "id": "U_1ED8" + }, + { + "text": "X", + "id": "U_0058" + } + ] + }, + { + "id": "T_C", + "text": "N̄", + "sk": [ + { + "text": "Ñ", + "id": "U_00D1" + }, + { + "text": "C", + "id": "U_0043" + } + ] + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N", + "sk": [ + { + "text": "Ǹ", + "id": "U_01F8" + } + ] + }, + { + "id": "K_M", + "text": "M", + "sk": [ + { + "text": "M̀", + "id": "U_004D_0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "text": "!", + "id": "U_0021" + }, + { + "text": "/", + "id": "U_002F" + }, + { + "text": "'", + "id": "U_0027" + }, + { + "text": "\"", + "id": "U_0022" + }, + { + "text": "(", + "id": "U_0028" + }, + { + "text": ")", + "id": "U_0029" + }, + { + "text": "?", + "id": "U_003F" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "120", + "sp": "1" + }, + { + "id": "T_SPD", + "text": "", + "width": "20", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_ALT", + "text": "*Symbol*", + "width": "120", + "sp": "1", + "nextlayer": "alt" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "", + "sp": "1" + }, + { + "id": "U_002C", + "text": ",", + "width": "", + "sk": [ + { + "text": ";", + "id": "U_003B" + } + ] + }, + { + "id": "K_SPACE", + "text": "", + "width": "520", + "sp": "0" + }, + { + "id": "U_002E", + "text": ".", + "sk": [ + { + "text": ":", + "id": "U_003A" + } + ] + }, + { + "id": "T_ENG", + "text": "⨷", + "sp": "1", + "sk": [ + { + "text": "–", + "id": "U_2013" + }, + { + "text": "—", + "id": "U_2014" + }, + { + "text": "_", + "id": "U_005F" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "120", + "sp": "1" + } + ] + } + ] + } + ], + "displayUnderlying": false, + "fontsize": "" + } +} \ No newline at end of file diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kmn b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kmn new file mode 100644 index 0000000000..f5ae9bc72d --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kmn @@ -0,0 +1,254 @@ +store(&VERSION) '15.0' +store(&NAME) 'Obolo Chwerty #6351' +store(©RIGHT) '© 2019-2022 Rogers Katelem Edeh' +store(&TARGETS) 'any' +store(&VISUALKEYBOARD) 'obolo_chwerty_6351.kvks' +store(&LAYOUTFILE) 'obolo_chwerty_6351.keyman-touch-layout' +store(&BITMAP) 'obolo_chwerty_6351.ico' +store(&MESSAGE) 'A keyboard layout (chwerty) for the Obolo language of Nigeria. The keyboard covers the need of every dialect in that language.' +store(&KMW_HELPTEXT) 'A simple keyboard layout (chwerty) to help you type very easily in Obolo language.' +store(&KEYBOARDVERSION) '1.2.1' +store(&KMW_EMBEDCSS) 'obolo_chwerty_6351.css' + +begin Unicode > use(main) +begin NewContext > use(NewContext) +begin PostKeystroke > use(PostKeystroke) + +c store(capskeys) [CAPS K_A] [CAPS K_B] [CAPS K_C] [CAPS K_D] [CAPS K_E] [CAPS K_F] [CAPS K_G] [CAPS K_H] [CAPS K_I] [CAPS K_J] [CAPS K_K] [CAPS K_L] [CAPS K_M] [CAPS K_N] [CAPS K_O] [CAPS K_P] [CAPS K_Q] [CAPS K_R] [CAPS K_S] [CAPS K_T] [CAPS K_U] [CAPS K_V] [CAPS K_W] [CAPS K_X] [CAPS K_Y] [CAPS K_Z] +c store(caps) 'A' 'B' 'N̄' 'D' 'E' 'F' 'G' 'SH' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'CH' 'R' 'S' 'T' 'U' 'V' 'W' 'Ọ' 'Y' 'Z' +store(digit) '0'..'9' + +group(NewContext) readonly + nomatch > use(detectStartOfSentence) +group(PostKeystroke) readonly + if(&layerChanged = "0") if(&layer = 'numeric') any(digit) > context + if(&layer = 'caps') > context + if(&layerChanged = "0") > use(detectStartOfSentence) +group(detectStartOfSentence) readonly + store(sentencePunctuation) '.?!‽' + nul > layer('shift') + any(sentencePunctuation) ' ' > layer('shift') + any(sentencePunctuation) ' ' > layer('shift') + nomatch > layer('default') +c group(main) using keys +c + any(key) > index(out, 1) + +store(accentibles) 'aeiọoumnAEIỌOUMNn̄' +store(accents) [T_GRV] [T_ACU] [T_CCM] [T_CRN] [SHIFT T_GRV] [SHIFT T_ACU] [SHIFT T_CCM] [SHIFT T_CRN] [CAPS T_GRV] [CAPS T_ACU] [CAPS T_CCM] [CAPS T_CRN] c [K_BKQUOTE] [K_BKSLASH] +store(nasals) 'mnMN' +store(nnas) [NCAPS T_CCM] [NCAPS T_CRN] [SHIFT NCAPS T_CCM] [SHIFT NCAPS T_CRN] [CAPS T_CCM] [CAPS T_CRN] c [K_BKSLASH] [SHIFT K_BKSLASH] +store(vow) 'aeiouAEIOU' +store(grave) 'àèìòùÀÈÌÒÙ' +store(acute) 'áéíóúÁÉÍÓÚ' +store(circum) 'âêîôûÂÊÎÔÛ' +store(caron) 'ǎěǐǒǔǍĚǏǑǓ' +store(acnasals) 'ḿńḾŃ' +store(spguy) 'mnọMNỌ' +store(spguyop) 'ḿǹộḾǸỘ' +store(erase) [NCAPS K_BKSP] [NCAPS SHIFT K_BKSP] [CAPS K_BKSP] [NCAPS ALT K_BKSP] +store(gravekeys) [NCAPS T_GRV] [SHIFT NCAPS T_GRV] [CAPS T_GRV] [K_BKQUOTE] +store(acutekeys) [NCAPS T_ACU] [SHIFT NCAPS T_ACU] [CAPS T_ACU] [SHIFT K_BKQUOTE] +store(circumflexkeys) [NCAPS T_CCM] [SHIFT NCAPS T_CCM] [CAPS T_CCM] [K_BKSLASH] +store(caronkeys) [NCAPS T_CRN] [SHIFT NCAPS T_CRN] [CAPS T_CRN] [SHIFT K_BKSLASH] + +group(main) using keys + +c + any(capskeys) > index(caps, 1) c by self to solve caps + ++ [NCAPS T_ENG] > dk(1) ++ [SHIFT NCAPS T_ENG] > dk(2) ++ [CAPS T_ENG] > dk(3) + +c caps ++ [CAPS K_A] > 'A' ++ [CAPS K_B] > 'B' ++ [CAPS K_D] > 'D' ++ [CAPS K_E] > 'E' ++ [CAPS K_F] > 'F' ++ [CAPS K_G] > 'G' ++ [CAPS K_I] > 'I' ++ [CAPS K_J] > 'J' ++ [CAPS K_K] > 'K' ++ [CAPS K_L] > 'L' ++ [CAPS K_M] > 'M' ++ [CAPS K_N] > 'N' ++ [CAPS K_O] > 'O' ++ [CAPS K_P] > 'P' ++ [CAPS K_R] > 'R' ++ [CAPS K_S] > 'S' ++ [CAPS K_T] > 'T' ++ [CAPS K_U] > 'U' ++ [CAPS K_V] > 'V' ++ [CAPS K_W] > 'W' ++ [CAPS K_Y] > 'Y' ++ [CAPS K_Z] > 'Z' + ++ [CAPS K_Q] > 'CH' ++ [CAPS K_H] > 'SH' ++ [CAPS K_X] > 'Ọ' ++ [CAPS K_C] > 'N̄' + ++ [NCAPS K_Q] > 'ch' ++ [NCAPS K_H] > 'sh' ++ [NCAPS K_X] > 'ọ' ++ [NCAPS K_C] > 'n̄' + ++ [SHIFT CAPS K_Q] > 'Ch' ++ [SHIFT CAPS K_H] > 'Sh' ++ [SHIFT CAPS K_X] > 'ọ' ++ [SHIFT CAPS K_C] > 'n̄' + ++ [SHIFT NCAPS K_Q] > 'Ch' ++ [SHIFT NCAPS K_H] > 'Sh' ++ [SHIFT NCAPS K_X] > 'Ọ' ++ [SHIFT NCAPS K_C] > 'N̄' + ++ [SHIFT K_6] > '₦' + +c (for touch layout) ++ [NCAPS T_Q] > 'ch' ++ [NCAPS SHIFT T_Q] > 'Ch' ++ [CAPS T_Q] > 'CH' + ++ [NCAPS T_H] > 'sh' ++ [NCAPS SHIFT T_H] > 'Sh' ++ [CAPS T_H] > 'SH' + ++ [NCAPS T_X] > 'ọ' ++ [NCAPS SHIFT T_X] > 'Ọ' ++ [CAPS T_X] > 'Ọ' + ++ [NCAPS T_C] > 'n̄' ++ [NCAPS SHIFT T_C] > 'N̄' ++ [CAPS T_C] > 'N̄' + +c for mobile longpress +c + [SHIFT T_MWG] > 'M̀' +c + [T_MWG] > 'm̀' +c + [SHIFT T_ORWG] > 'Ọ̀' +c + [T_ORWG] > 'ọ̀' + + +c English equivalent (for desktop) +']' + [CAPS K_C] > 'C' +']' + [NCAPS K_C] > 'c' +']' + [SHIFT NCAPS K_C] > 'C' +']' + [SHIFT CAPS K_C] > 'c' + +']' + [CAPS K_X] > 'X' +']' + [NCAPS K_X] > 'x' +']' + [SHIFT NCAPS K_X] > 'X' +']' + [SHIFT CAPS K_X] > 'x' + +']' + [CAPS K_H] > 'H' +']' + [NCAPS K_H] > 'h' +']' + [SHIFT NCAPS K_H] > 'H' +']' + [SHIFT CAPS K_H] > 'h' + +']' + [CAPS K_Q] > 'Q' +']' + [NCAPS K_Q] > 'q' +']' + [NCAPS SHIFT K_Q] > 'Q' +']' + [SHIFT CAPS K_Q] > 'q' + +']' + [SHIFT K_6] > '^' + +c space modifier accents +']' + [K_BKQUOTE] > "`" +']' + [SHIFT K_BKQUOTE] > "´" + +']' + [K_BKSLASH] > "ˆ" +']' + [SHIFT K_BKSLASH] > "ˇ" + +c English equivalent (for touch layout) +dk(1) + [NCAPS T_Q] > 'q' +dk(2) + [NCAPS SHIFT T_Q] > 'Q' +dk(3) + [CAPS T_Q] > 'Q' + +dk(1) + [NCAPS T_H] > 'h' +dk(2) + [SHIFT NCAPS T_H] > 'H' +dk(3) + [CAPS T_H] > 'H' + +dk(1) + [NCAPS T_X] > 'x' +dk(2) + [SHIFT NCAPS T_X] > 'X' +dk(3) + [CAPS T_X] > 'X' + +dk(1) + [NCAPS T_C] > 'c' +dk(2) + [SHIFT NCAPS T_C] > 'C' +dk(3) + [CAPS T_C] > 'C' + +dk(1) + [NCAPS K_S] > 'ṣ' +dk(2) + [SHIFT NCAPS K_S] > 'Ṣ' +dk(3) + [CAPS K_S] > 'Ṣ' + +c deadkey for tones (touch layout only) +dk(1) + [NCAPS T_GRV] > "`" +dk(2) + [SHIFT NCAPS T_GRV] > "`" +dk(3) + [CAPS T_GRV] > "`" + +dk(1) + [NCAPS T_ACU] > "´" +dk(2) + [SHIFT NCAPS T_ACU] > "´" +dk(3) + [CAPS T_ACU] > "´" + +dk(1) + [NCAPS T_CCM] > "ˆ" +dk(2) + [SHIFT NCAPS T_CCM] > "ˆ" +dk(3) + [CAPS T_CCM] > "ˆ" + +dk(1) + [NCAPS T_CRN] > "ˇ" +dk(2) + [SHIFT NCAPS T_CRN] > "ˇ" +dk(3) + [CAPS T_CRN] > "ˇ" + +dk(1) + [NCAPS K_HYPHEN] > "¯" +dk(2) + [SHIFT NCAPS K_HYPHEN] > "¯" +dk(3) + [CAPS K_HYPHEN] > "¯" + +c make up for +'m' + any(gravekeys) > 'm̀' +'M' + any(gravekeys) > 'M̀' + +'n' + any(gravekeys) > 'ǹ' +'N' + any(gravekeys) > 'Ǹ' + +'ọ' + any(gravekeys) > 'ọ̀' +'Ọ' + any(gravekeys) > 'Ọ̀' + +'ọ' + any(acutekeys) > 'ọ́' +'Ọ' + any(acutekeys) > 'Ọ́' + +'ọ' + any(circumflexkeys) > 'ộ' +'Ọ' + any(circumflexkeys) > 'Ộ' + +'ọ' + any(caronkeys) > 'ọ̌' +'Ọ' + any(caronkeys) > 'Ọ̌' + +'n̄' + [K_BKSLASH] > 'ñ' +'N̄' + [K_BKSLASH] > 'Ñ' + +'s' + [K_BKSLASH] > 'ṣ' +'S' + [K_BKSLASH] > 'Ṣ' + +c any and index +any(vow) + any(gravekeys) > index(grave,1) +any(vow) + any(acutekeys) > index(acute,1) +any(vow) + any(circumflexkeys) > index(circum,1) +any(vow) + any(caronkeys) > index(caron,1) +any(nasals) + any(acutekeys) > index(acnasals,1) + +c change backspace behaviour for special diagraphs +'ch' + any(erase) > nul +'Ch' + any(erase) > nul +'CH' + any(erase) > nul +'sh' + any(erase) > nul +'Sh' + any(erase) > nul +'SH' + any(erase) > nul +'n̄' + any(erase) > nul +'N̄' + any(erase) > nul + +c virtual keys +any(grave) + any(erase) > index(vow,1) +any(acute) + any(erase) > index(vow,1) +any(circum) + any(erase) > index(vow,1) +any(caron) + any(erase) > index(vow,1) +any(spguyop) + any(erase) > index(spguy,1) + +any(nasals) + any(nnas) > context beep c prevent certain accents on nasal consonants +c notany(accentibles) + any(accents) > context beep c prevent diacritics (stacking, on empty space, and plain consonants) diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kps b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kps new file mode 100644 index 0000000000..60ba61477a --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kps @@ -0,0 +1,121 @@ + + + + 15.0.206.0 + 7.0 + + + + readme.htm + + + + + + + + + + + Obolo Chwerty + © 2019-2022 Rogers Katelem Edeh + Rogers Katelem Edeh + + + + ..\build\obolo_chwerty_6351.kvk + File obolo_chwerty_6351.kvk + 0 + .kvk + + + ..\build\obolo_chwerty_6351.kmx + Keyboard Obolo Chwerty + 0 + .kmx + + + ..\build\obolo_chwerty_6351.js + File obolo_chwerty_6351.js + 0 + .js + + + welcome\chwerty_default.png + File chwerty_default.png + 0 + .png + + + welcome\chwerty_keycombi.png + File chwerty_keycombi.png + 0 + .png + + + welcome\chwerty_mobi_alt.png + File chwerty_mobi_alt.png + 0 + .png + + + welcome\chwerty_mobi_default.png + File chwerty_mobi_default.png + 0 + .png + + + welcome\chwerty_mobi_shift.png + File chwerty_mobi_shift.png + 0 + .png + + + welcome\chwerty_shift.png + File chwerty_shift.png + 0 + .png + + + welcome\chwertyftkey1.png + File chwertyftkey1.png + 0 + .png + + + welcome\chwertyftkey2.png + File chwertyftkey2.png + 0 + .png + + + welcome\chwertyftkey3.png + File chwertyftkey3.png + 0 + .png + + + welcome\welcome.htm + File welcome.htm + 0 + .htm + + + readme.htm + File readme.htm + 0 + .htm + + + + + Obolo Chwerty + obolo_chwerty + 1.2.1 + + Obolo (Andoni) + + + + + diff --git a/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kvks b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kvks new file mode 100644 index 0000000000..0ba3c147a0 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/obolo_chwerty_6351.kvks @@ -0,0 +1,114 @@ + + +
+ 10.0 + obolo_chwerty + + + +
+ + + ` + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + - + = + ch + w + e + r + t + y + u + i + o + p + [ + ] + a + s + d + f + g + sh + j + k + l + ; + ` + z + ọ + n̄ + v + b + n + m + , + . + / + + ' + \ˆ + + + ¬ + ! + @ + # + $ + % + & + * + ( + ) + _ + + + CH + W + E + R + T + Y + U + I + O + P + { + } + " + A + S + D + F + G + SH + J + K + L + : + Z + Ọ + N̄ + V + B + N + M + < + > + ? + + ~´ + |ˇ + ₦ + + +
diff --git a/common/test/keyboards/obolo_chwerty_6351/source/readme.htm b/common/test/keyboards/obolo_chwerty_6351/source/readme.htm new file mode 100644 index 0000000000..a4f9c5d456 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/readme.htm @@ -0,0 +1,29 @@ + + + + + Obolo Chwerty + + + + +

Obolo Chwerty

+

This is a keyboard layout (chwerty) for the Obolo language of Nigeria. This layout covers the need of every dialect in that language. + +

NOTE: This keyboard has been modified from the original for the purposes of +testing https://github.com/keymanapp/keyman/issues/6351. It is not intended to +be used for general purposes, and is not the final release version. Changes +made:

+ +
    +
  • Files renamed
  • +
  • NCAPS mismatches have been resolved
  • +
  • Font and PHP help have been removed (reduce distribution size)
  • +
+ + + diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_default.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_default.png new file mode 100644 index 0000000000000000000000000000000000000000..097553943ec1c63b96e64afe5a8ca52745d77e5a GIT binary patch literal 21265 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 E4>7{nYybcN literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_keycombi.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_keycombi.png new file mode 100644 index 0000000000000000000000000000000000000000..a71cdd524f5795e5e745c971482b118c0faeda17 GIT binary patch literal 24345 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 literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_default.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_default.png new file mode 100644 index 0000000000000000000000000000000000000000..a80191a56174c80dbf38a2055b8a27d8479defd4 GIT binary patch literal 26988 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 literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_shift.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwerty_mobi_shift.png new file mode 100644 index 0000000000000000000000000000000000000000..c9fca97313be6815c4e4280f83d26f62a5c0c9e2 GIT binary patch literal 29675 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ቅKN|gTgfOb-Gu62n-U8f8%Qc@GS8q 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 literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey1.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey1.png new file mode 100644 index 0000000000000000000000000000000000000000..66406ba6e499120433cd991b5d05301dbf913ece GIT binary patch literal 8096 zcmb7p2|UyP^|Ns7uJs#Wpc)i}QyHW^7DQR)2uXkn;kFbg+7 zD!CM=F8uBNWLm4hHTTvG6=T|9j&17wv-}N;Y7JKpSQt9K{8DQknQOD7HDVcZ`r5+D zHPfjt_)$&S;j1@9bJ5s?a>w?|l|6ooT& z%&cSud7rJme)+8bk-L+(gFi#&ZBAa^yEWG5uQZy;^}~uo#tUmmM!0cI%!1%4)3d^T z(x>JUM485M>$%t1Jui&d0s;boC?**jWajv`5;nU2LByNIV$m~!dh8X;u*ET$n+Cq2 z!Jre5w?JI|pl{bFt+?HQyb?3R7h75Bl7fzJZM{jKpYIdnU5W5Wse15e=>qk#;a@fX z_^bVMLXGs*RdiUsx`MJY?y$EwOaK6QGI;Wzoj%y8$m{zrk-q=KA_-A%-1=fvz5b%u zdK;b(0Qh_u%5Ixn?{{^}ux)Cj!*LoVEzn>#1BCs2vshxbz4+mD=AE`;<=5toreVPY z;e0-IKrr`X|6xXuulMmHM{exZZ1Tq5TWzeNbz^J#C5^Qu-~Srk6ORc+A2P0~{9^NM>T9yr;bZy_I}t)oVGVPPaRvR}5i zE3arhJH)SD_uQafPg!r^sAAKo@u5)uxV8$?*Z6xG0wi1QvDNXKOcu%W}(=^)O8b}Tt2Xl(x^B!F>`YoC93bY zGLQEt4$)I7X+g;>+10*dewn1?v6C%Ub5tFn5RadzO|Utl{(iq zDoi+RcQ4d)gBT#w?gZ(=2f7#`YpCZ&Q1gpRZ<-Fz!;(@kh59z*x|3zJ zGaP27qwTY4$0Q7@pz2hqEK9F}pGLDozg$;J@`<1u=@Nb?P$7o8XnR8SgHuyc=kMZR z;Pq3*W-;$)&EyQ)#YZHZUW2*$`~1nsb)P^v-9<8*h^ARXZf2Bjihq}sjq%@YxeLi{ zb$rE7{b6A7tcyrL(z~7r?dimSNWDb@4Cj>ukEDhvX&{b9v)`>M@AGov+f0$pH%v^7=6oS!B$&mS_+BP@Mi&Xjaljz4 zY)wtq!Evu*`eIqs$ZW+q2b!o)*UaLN#nwArSM5w+?T>x>qY8#GMKx{Ue;jSt=lJ-Z zVc^XHVW-?KFE9;rmmU z=v0(ii}D#7szG>@q()5hS3XBC?-`AIqY*y_14WUNAK*`Be}E0tE&gVeNfY(5aaF0X zR5h}{-TkP9xt1E)WLH#0TAFe#M!GSp&v{|O;Zte(QuCsW6GEKmx;MH0w=fQ)G1}*K z7RbmGW#=H($R)cCmyL^k`)QaO{&utRXA^0L7DA0ie5+GQs@yQgwp4&!OWD)*P4c+! zTPttQ!#ULTD(G&`h%oseI&brvpGk(e^~Wy_c{$d`@ug*fer%gpstO(jGxysw+MS`r zHB2WDSS#ZDdkaoZv_;@1QofOdD{ty`=)bCnc@S>mZtKLqR#waS3QoY0oqn;m^`V)* zN?Z@on-)6wZ5Id!cKoi^wCnaaDfyX-%wb}-b;<@`dA=GiAp7<0eYVhr$>G$S zgb+>#uy%v=Yqe*iYK!U8tu}rCihiPd*UXT=irN&h?#=u=`&wu3E7~}m9dWNck$;DKvxWuh6vsMx+#{aWru%3D0_wYKT$t%fVgLLw)w@y*#PEjcoY zV%rQ+@ostN__dug8di+1BH0OH?;QYuU5Cexk8ht0?VaxTv;Hized%+8onFSN?zdAF z!ySypwNl~0g?qf4@oug?(TSeC5-Gj;8DBjaCzicIIS8$H8@kpIWN(R3`zNspGI{r5 zrYF}p@Fuh};yY`!@WoTp4@~$mob_fSm-WgQP9Ij^*vlI$YGaOs^N^N;GsF{Ic6R2v-{HRq`*)7}9mIIwezXvRh1pyORgF+67?Tm^Y(e&V zlSLDX#$yF9B-lD$L0;|z)8D1`U^XFX4k#%K#P8(j`ny(R>u@19L zPY;2$F@e%fJNg=9rRod&56cWj``XTW&`+G0^Q|Q*`5MDr@5DIL<(mSZ=8l?#+keH$ zld78`SE@z`p-RPG#Ejzh!wtKI=6Nr?!}_j!4z0yIC3NH0TJ#5KQG*=Z?rCI&Lcu>9dR ze>BCO+q5A)zzHv2)pdR3zhQ9X=RnN}OTY54LCq^2GRkbodSw3Pi^3JZ=b&?y*_f`* z#QqGARh259vbg{WVRbW1H6ecYlLV^F6c_S z>eJPv%a#eu5*S`6Ixp*Y3ykFKNwudBJ$R~M^1Ykkamr}-J>gIU%e zTf#-9j9xn+hkA$Mb&B7<3bZL$BJ3mri?EFlo+>GmN?!K0yue^xIg`fjdNMWt@tyPe zJdpu!V-be~kh$#R-Ka7s?>flhr&8V^ zf-Wv=BR&{j1bNgg@pOeZ_=x|r41u=V$d0idq}Ongt%HBA$jleT$2Bcd^F$4ro|-~K zbr`H4J$|~pj>Ke)J?&W(XzieQx#+8*{A^Z%vela!=9OGOdW5;z<9jKDjZiDxcIN#A{2E=#3* zKFHMl=oXV*IZz3qDQ<)0IlHjOjr#fFF(OnEXIvYYIt z&z1*@32|u*j-yl9h6deX_jVKckP!pw!(;yaxD6`eQ$jr3Zc#vH%kj}`eV|ZK!U^3^ zutjuv`8a~_8;{+;_=w)47!M@!>n{88e~_2oBfDar zLHc=o<3n(k6*k3C>K6@nYL zQx9@ty5DnYsG1t+>Di7ybx}(zSnXxQwf~p5zUGA=@y<|mVp9=WpAsM&3`AmOf<)=) za73uJP1VR~I1KPe-rmvi9Qpe5ZFBkuca2#f4tZy&II$Pq5Z=;R3o$GNMK1)dWNG|s zS0gofo3JV_9yt~{t9I`3+syjdxOz%3^V#7orumM&@w`ODoR&3rxX;2zcgMEkD2j@l zyw)`70`BiRyDejG%SKLX?8|Pp!Z{t=mM~)0^6!YiI?z95%}0ZOW3a!AGz zdb8N8jTzS~ASpQwk|TkcqA3A*^bsVFnXV7Qny)>iqLKOqg@qS@lYJD|Y=G~+;t=h` z-ZpBEpioOcG-W5#w*SWOX2HLS91`NWSSgnhZCLV}&m;B=Bgwe40|FAwzcfdK^kPB8*`7U~e7nv8kmOK3(oQc(dh)8~&bw?#hPw->w`_<*u>L21a2Ev%hZu1D$ z{0Q$sp+?1#@qFOWZFz~ekH?4xuFS${3wbopa(T9V^m9(~O||=&-LO#6yDF|xA-~*F zti^L=rJQTif!*iMuij8Xa?887EMQe-53V)y-Fik(PP2Fl z-(3%ynY>kKA+s%0>|v>AD|!x}2oJz{nk}zIv>A9Z?oK8ZXtzDIOk(MzYYfr(u1Wc1 zFd{yoN}$ie-X(%31on*m5dTICOR^N2Pm5tuZ$Gn(0{>z!DI9wOGJqH8{{*!g?Ssf>4?8Q19c zweE3p;ev1&B2+{kGBbVM>KAk5mF`Po&u&oy#! z&t#Y~3%;o;fM`8lls6?PWc&)WHrEZVy0BY}FU?v3!ymei#BfF{q`Pti3R?9`uw(3Oz8=p#YIle;-3$Iwj0O?$xSxH>FuhkgAY9_Z3Pg z-`t~5-*pA?)AXT|2Hhs%*Ux!ge|^AYFr#bDStnv@sj!C@;(?c_eNuB&q07NWEAwts zCvD19z+icu7A7OTi$N$}`Yp0axR!6i*{8ruiT{=k`EFa~naNI55qRw|h%IGwOE=K# zUW7QT>bG9=7`D{gqx<9!2K>Ut`Wj>}lR|X@5*U#Cs3y8Vh9naLyE*&Rkt3L%n2kMp zfa);NcP~c{2xd907#`mbHg~;b+au_tnbw-_@TX%#B9R_{Sg^pGM=myrT(Zy;1N(yi zaA1fXv2px+_NW7aChWsG9D$4DUD=en-bHu`cR3Y!PG?{Qqvo2#lvYG%yYJp|F=|fr zFP@&v4h|+Nc{B^O0V*;X1D+``-O@#TIb>l{EfuLp$L;d-hm45o^)t zeB*=@Lt0U345iDI3Fms*VV)a<{kt1$@57aqU8xT-xvjUnRFYME*t-;rb(Q9UJD`)% zvBg*8W21F&PTJdI;n-bF<9|}eZFYX1i1)={26;QEoF=PplhbD&ImygK|C_1WCa3XV zW5$%e!2_OcTc|If_V#uw>ME@ix5^Fp+9HkUz$^YU)D-EHj~NN7dn# zLqmiL=Cqo+`XtCUV92F&PMY(Jof)UaiKGRNU>?f@AN&2XrGRIz$t3!k0GH- zzy^VBZ$GAYcqUkfq%5$K)!%f=Wn}e+WJ%w+JIWmmVq&tncT4AW%yCw)&I;d>1f3Zb z27JDjxF6PgrF57c+V1&!(<-6(Ajb8X&aYqt*YrCo!Q(3;6?%DI-j47oKhi;&_Kgs_ zKJ|%^elH8L>b7p#tEg0BKOV!&KhvA*WB^a%9#?vNQtTlP+*&IZw4pq*uZ$qpsq$f$ z{J|`kEdE?PUU0ZCd)DgGQ1Kncnghb7e>2TZ`t_PQ;)is2e)duF@gS_Wu($e3{^32O zgP@?qV#Vxmo8jlz*U1jtyig~rPFMINpCiM4g!^pS^~9h;Cqh5H;QEO1#_5`5zX!Z% z^L4M{C;G?aR;Ot!PcgF$k88U;JG&M0mB;q&k!|*$_t0}PuXgB84QhU!;Z&O5Wr`#X zsHgP#Ak0dgHuD_fFeBpzanu*lNyHUdRON9LgA2x~Nyk&w0diyQzWOdEEU0fs= z`i{O0mMj{QydNDfPzjoGXTu4%ZW#$l3D}^#^{oO}Gi%`G$2Np?%cuTvarbyGh>Bea z*=?tQ$eMm(?_HOas49Q4_#@k&X=}*yOq-U^xAD4ZvO$u#5wwS??8v!+n4JI};RV#p z8}e~&Re@9X!*^74-@Vf);`yi9v3Psx#0O5s+-2r6gL!Rt|>d(~| zQ}aNW<}Pdv`)+@h^)v`^!S_LNm#o@6*_KJ_vsk3GMOlaIY6uEZE^$B+A`0nCnq5c z8l1wm593(2pyceO?zE7f1cE_mIwsLhd!bp)rb8*u+wZH_nKU9k_5|~2!6f-Z@|)W< zSdFEm>>Yi=a*}zrWn^WOT#%QaPf4wnoV%%kG9Xkj1&0r;qz1C{+UjzXrhHXjjS{cx z9qSG?aC;@~aauZjC5%1a#p%mY0{IkdJ~XtGu!upZfF>ISG5(&RL04c>Njx26VVAS7 zrlF&I7omNA2KtznBkF6*HnkpB`kr(-rPrZQnkOEujRdAj%g=60ZfDBya5@@|uBfYn zrc`+Z2ipRHK+f(n%>zydI(GvPWc=hhW@XR3LFnZ$YB{gNeLI!b`NNsTPHWuo&Bd1V ztSsFkih5*Z6N`R8;=_{5 z-j_E3-8Xpa2&=%?DjQ+-Kl$DMZE5Jg2W%dSA=miJT;K8_$T#>;wEqLQIe+6eCXFF+ znF59WXWTxNp>s6o9D_$c`2M|^0Tj4Af!E-ZsUX)Xbwx~7CNCkgLXtx&de`ea*0s8@ zjCxNVvhR$&I@ZR*$og$+9}h0_GY!{MZ=w^4$yr8q=VWCm?xLl}#U+e(RQ572PI{Lv zzW;tre`yE;F5FUD{<=USmpBcB@chIm+Qd9za&pqAVzDJG%qftax#h?DC8WHy!uzkk zg}k)O778-q_2=(c>TglcJNYj}-cGFkiz4K|!YuSz;tn2qO5)O;zGUBNYJ%D$Of4-f z1KSF@pKw~ogGS_Nn=b=8Yjy$DPQ^Qk8RH?oRqFDgTN&;rTbE8XbPg?O@GJ#&d8ArV zB(4`qR0n((m&7T($h7MD>`ThqsIxewU#g3}3SUl7$H1lzP-kwRq16p9bxGC=op;M_ zPj~wZN_+0x_S5DOh+#PTH#D#Yc`$5sD0&Fkr^#3RQE3O@xkO8;z-hPL5@OyY@AI~! z-Eq0@%8OuOE_9rnF0WLx7-8cxnXgs{KR@+-ne z;ppd=VZ+!(LpWTy7W@TT7rZm5jW@iLhP+-s&kT64rF0&+_;kK*&|E8c{HFqarg|ID z#ybg^7e8V`cnw6|O2J3tgjXk!J8J@Y%dOvk2ISc(xT!0V7s6)Qy_NXdAH-B8DTYFE zP(`oH#o>&*pIiq70RT|c_`uiK- zFg~AgU8(V)*`v*y3lVK<`G%b+DF7gSPfKb0N#5|a6(0EL6{LNV%Jj{10r{z3xjY=dyntn_Q*s3XnwNn<_~ZuZ zjb?b(E1iB#S^aE{MtY^^!2B79=4%=pYkP`KUAYT<_mg4NpKq35D5T`a^zwF)3vl?F x`u`C&7pJxs0NgGG$wI7Sub%cdNL%6VxO=l=#ReMnkXHh@dCl}H%J6=~{{h3*GnW7W literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey2.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey2.png new file mode 100644 index 0000000000000000000000000000000000000000..8554a69418091932acbce7c532f2c605209dfe93 GIT binary patch literal 8306 zcma)>c|26@|Np15CX~{IO64vwA=#1`k`!5rvdo~!z6^;;V#-?9y9E&jWoN8oFqjaM zWh}#BFl0B2EMqtG9q!Nld)$xj@BTf0pFd{KIgfL$bFS+;=XyQgulM_{v7s*iLD7Q% z0D%9_?VI-jfc+Kh{aPL__Wv!2#_ndH_kG z_sutBzN-95sVRe68mEG^qho2j6sIe*qcqTcqs5Q%9tV`&p@Bci_?#>&dzBq{RnBJL z^7RKXr%s>J&|4ZF@Ex+|~UK+ZbwB za)J^5X0uUeXFP-Hc@I&UVa#f12ug8PU!#wFNU*0RV>EsS)9UMAr+BwWB41|6r6TCm zFjYmxuY-dY^MbsL@W{Vg>tqHVb;DpVw4Q!>C8f-fk&(#VmJ3uNmAeM&X9vRm`J5au zRBK18cw}&}1YaIDH8o`xBxC2c4*)pK%K>5c_U8WjaOI-j>v z5w{l0ubpG~jF#i8zp2U3%i|iXcl>*QGNP&(Tdty9P!u_tpx){H0^iRXsBadjscVR6 zHj&C~SFFo;juewAN@zMkl3wQq!m`JnT%1eoYAxB$x@P5nG?Os{kE2jlMnfU(Z@VWt z)nx*yvxzCa{VQ%yZ^lCPC*q!;rIfTSWbVWZt)?qjyE!{gqPDG!{foG^o(}m)iAx7RUO)~$9P%B}yW~s>1s{N> zy*y!dIkanDe4)?$@S%kk^wL~dz>T3F1M$OzsHbl=#5AxUuM~-4@R>7_S_6WKYndW2 zzvk^vs5JuQQwi7(3aa)Jx<27`>In`1Nh(LhPe?DH1+N`Tu0fq=p`|*GyxG~D8viVy;47ni;KmEqSKUm?sq+Uvzp%br7SH>`?!prX)2L=SLDSpA z7@6FyB>cyau^wc}V&>CD%4TXx;U?J~`-QX^LMJ^6B>Q`9-;%#(cC*->ce;JC zn7Chrx7BN!o@_j|tKIYX(bAKyJ{sd=#_=Y@?q1$y=>D?RyB{h*IQ0$FUIE`wxDf}g zarEsyn;RJDX!y09XUSC%bsGbMt^ZH`Q^%-{@B7VgXeIN&<8o*41>b#e&#r!B*7Qs- zIA(t3MLswrT-lEE7iu@r!zW16dwDAE&5(ubM~pw?V^YhD6Vs3BpEMVBabKC#a{&@r zxn7}uwCR&>UfzCgv|Q9SaL95={Hhc(AZO@;PadIR=Y8 z$8@Y>alEl3Lv8lp z!Y468svW%VH-@GAb|N5WV<%wJ1$M+*f9?dSgfw&#qs?1$xq33xlvOq9BOH$;BJ3I5l5?lL=-T)X0E^!n6;!rcaV9 zJ!}Hv2gb+8-vtx^{rygzJo&u$Kib?4#DmxHVNk_?mvv@nD5pCN=IZF!qH*+!!tfa> zdwsd<*!^v7Z9^j?acoKmS?=lckv-`q#EN+PHx;5C&;FA>96>T{H9q(H5g!2X>h_uc z?pfU(}@mYpidF#x4ny$cgp70RbZ#5q17+^bJQRR78_4LHyj`?b-Z` zxUrKJsv>-|6!C_0Nmhu;gTXek2xJ1Dvel3#N5; z##jj%uqT9rbeK(1Hr@X294H6OQ-PYPJ%f+qg3u$_efe)j{}-|UbD?f>r4Yds@7m<=IqUVQ^qB>Pn(n_R6c} zZeh*y$%JvA!f5Gc<&d`d&;6s_?_w@g)Aqy5C4oMZeRbDtfoTqAC*9VRkcLumOIeG; z!UsX3DzUXv>NuFq0f6RPI`1i&3w<7r`_e4a1$1Wh;>v$zRa5UzRF8rxRY(2 zuqsz%N+>{bpYmyjTW25fV+@7%I;om&64WUDVq_4&&9&XF&pegzpk*Lmj<<*kYC@%&2K-5-UW<-X^U zhWYqblxESYu0+yH2bE9T5z~r=u_Kg@n@%-$S}n<3w30`#YuTr>JEN{Q1;nZpUQpcr z)_wF)d4Z?gX^P(9!@(`R0iC*rtW<6ZVdXkg*+46DS($+|E%Cw@S05yGJEF}auS`x7 zte{-7I;!Q|88QeQ(!1W%+o=jZHVyaI8-DuLq$}iI<{ies@eiqY28-#R^hifh)@xP^ zf2@>{_2N_<;ho7{=~9#MIMBw3(iWj^7zL>>enz$n6pyc{k=Sn;UzG-)wGhl&mi-M2 z5(9()-8w$w$d`YhDi(yOh0Ble8h7>j`n=<9^}HbYpYH3(=ZiJ$molbE~o? zyvt1aua^h|3_WIYW!;Ou{>meWK3N=g6h1O1u-53;`aAgLLknQ|xigA^_$JR-%n11X zhnbsNe4okw<8oSG*0+!!>|Q%FY}iv!(FaBb6to@*Uu8L+#M$?UKuHl48_B+`*H4Om zEm}tlCkztfF{`PYTT*e>_KfNVzKX47OX&d>WDV+ubEJFm{q`r8KA*R#-#8k06^`dN z3RJ=w8Qex|BO&p}p6Mi}f!Gn&3er1x&4OwGBHDo?V;;K?I(D6*)s7yY{MBR^pNlgR z^~(F);9@l2{pM7}@*{oTg@Cko?Mz2w?^W|I`Q)xVS4{Fj*=hYfk@!N-|=AhU}FkQ+42>L!lGrVT~r)?wxEV2Cag)_965#&~V zDebu2X@$4yDe(yI%gfiW`(v^<>&8KL9!5u>AwEa8)EsEHUG!CALt3`Fd(*`Ca|)f8 z8@tp|EhiE&HXOJ?sF*lcR!d?m{L<=PjBIXSpe_bF-8hP(!hcq6t9iPxCWe}jsXggX z!-a5T6?^R?5g1n)YeB|+?$AmPQ&Dru+7HQRAFG7uTod6?ANm{a~s{ zf7cHaFXwkkOFiHM+9N<(X{mh0%qZQJRi*sk#o|ENl?hM;8H0cqm=R-b{OtE+FlGbc z&dQsfn{%`o#93vUq5PLFc-IngDOsyZ;!w#ca7EEFd!ix@S%(l_p%m17=q_WrLZm}` zA5|B?a4hc4)?jeI5lit4YiW*kO-X0puD3YzgmI`S;lb%=R)?^=+K1$2R$_S zR0w}n_&`PrV{t%s_Zedm&|^-Ghf0CD7iN_q-_Gw+k1*)>x+1ZW>etCv)gk0*$L5^w zYDqtl$Y9e;4d{-=Vwo!bhxqvi&wC`Mq+~Mx2^69Z0|_rO_g;KBaCe7~k8fynw7;{H z!c8e_pjyb(Fv@Fcs57c^ZA0hn>sN=+uB%7bz;Ss@KLWW^2tQZp!Z=j%T5sQ4UL!5E zzQ24RqxAnlL$igNv)ozCqQGUel~4eTytTI4{Wkw#RX4HYoD$|HZ|p z=}f(JAL3= z)41Yp$Vj_BtK6Gm)3?SD?5!}!-g^_~K_?J%JoR^dWF;Vdm7#QQSZFs|ana1Fty%Jf z!1i9A_eV^BM&SI2%ie`KLWSs}1!;&oZv}h)9MjON^L=G~@w?xZF{h;~WhT#(eM&R; z<-?s_2U!4G8Vqc*m4}J;C0T`Wc|Rk0S(^5%k_;>RZwZS<_optCYz*gdJ4+BXqU8j_d&Dpvo*r3x~Ht{ zM>9!g&iU@OVG@eh2a=5U;=A0B_Z>vZ1curlkg=X6>`#Wzd{zplOK;)ZFFNN*v`bws z9=kW02oT=7c`nigQ;#!^^;9|fJxwgvs24k4w&z0o( z^BePVijUR(20ex-l}svl`PK9vKnx`;hou*Fk8kVJp7P|FoZNjoUdSWVOF7>k24+qP>ACq<%fy=H&ipl0^#)7jYHYWP0nn2jw2U{Xk zgM7TkL>QalFO=5Uek&i*U6oSC`&RwEK801|9w?RFne9-uVHG(2?YU#GC8d@dqr7RB z_`w9BaIJ^K&I>@sttVj6Hcqu(6&*f{=4L-D>PF2PWS8Q?#-rupB5jCk?Gp*y(tprF zAC$G=Hp_|c;~ymq#D|#|=zj2hr{Lk62P)!>@bNP9SXD(`yHb z=~&~>BOUKOb2SVY{Wfxj;L=@DQt!(W6aIyH z;B~uD#o>X*lpLH}mt3^)EE!`*-dFZ;Iz8;ap+Qcbv0GXfqK^U&*n}r?BE@|&#I7*D%8>s&_ zQ?-yo_d5_06J6p1-PnY`rjTB8jNFxVQIap<9v(V-j7j5CEpfU5lNzna4Q9DILT)yO zpQGZll}u*)%suOg13m%HvZt3D=I$3?_p=J^`6vqZt3~LBMv1%br1R|hoVf>&TkF$# zM(Y>fVYHQj%qLjW12nxnh?Fx&E zT>bqaYH9}0^!XHSo|Uri9S`lFnzE6^gFN+&0$+ht{C1aYDHqSqoYCe_2Lg;K(l zv!zGE)!BE_!$7i~ppd!i~JAW$<0UroHV0ojRVt)M+v+u)pD*(yB~ z6QdQj(P4D!iVvQj0oB53_H}PB{cyC7N9!lie#rx5W(YKT`*UyE8_s`@RoJWlG(fb6 znpK|k7N@<#x`7SahF2*Vm(0%+iil#R2}f ziwxBvuKauQ%I}1(t;u&QRN6x|@FEO-ez+fXozRa(_wOOz^tGqIUo;PzYnO*c=Z&9k;sl zmX`}YQb2qaM3hxoEL+=+qxH1tg=A(*0Ku}s9O%de>9rLTW+y+F@xP(M zkxe<^n}0hwcB0dM-p1U#*c-jU4k#*O4PUOV;Hh7n@>fQq^8;BI7E;9a@}J4rtgNgE zZEon3YDf?Y2>gd3G&7x7sb4Mio6SZfmBbouErah2>UIlFZ}BgUhSvK!&aAw0B3_b{ zLmsRk2dt&AvOyZ#zqNhc&i<91-Sd^GH0GIsI>Xb_I8W)WH+(sw=^~>xf3E2T%fNNm zBg#=Y`dd1*X3S%sBWI(7uQkoFmVC=K_t93f7)+7DW@yG#%{REUvD&J4?cAxfM{aFzIpN~0P9dgEfj_l$!$v893Ig9vU&M`^q;NBGixySTe6EmXz&Hz|9 zj03?$Jnrg7Jo~!>ge=SlyOUn^%QX`cqi!HF&X|yq*EFxH9YTVyM zHVQVk%6^h805QMd8@5N!?TFqG3^mRUWMUxpSx4cwA=YvO-PuV zUo}am|EhaKe?o9Gz+X68t%FkUzOq5FWe;QvkIq$ics0Jn7R#PCN#x(Eo_@cM0r$7fAY_Oc?rS%@?pNj=VK{Hv5r_DQibL|*^|cdgB`PT< zv97HyyRckU`1Eqx^fJsyLppcxB=puZBHAFQl3DAlls?WK!wE9OAWeMMW(Td7pBwci z^&V_JjyCttYJG=Y@#VC}5;-%!HZf>jDI z3j%YJ;hQj1R zti*>G4m}_9xf9;gbVuMyrR7uo&;9=DOzv_P?pV&?P}!a6tMFR^ah4!z2|u9pz3r*@e;qe#R(|h1 zl}x>7-R%POC~OODnyU;J1C#1fqq$Tj#PXHC$ka*cM=fe#wuAD?ZE3&GVB-(=Q+K8P5|@F z)fQ&#eX4~Wqe+(Q^?C;*=c>@ee$`Go5{ zs&@VQ_0m{0TXJbMcN&#CaNfhx+Pa@kMHj-onC*Zoc ziPQ|@?=3QGl(pO_2qsXeZY6<4wt2aSc=MN7fr=3BrX`MWpJzIfgaX!bBG&m6pI}j* zxI}Dd*7GC0LAfuN^lcEkNQA?z&a<3+v{;(t8ZjPmkG{WLbOV@(5laUJD8FZfU6lDM0BJoh0y zqjOT7ZM>>VANkXUl(u--cXA5c<4I&&6?|bdR~Qog(2|^B0S5Xlcc{=L0GelxNA?9E zATblfjUOh_Cd`c*p*?_{%u`ZQV(6JXSF*GZu<_l2hOjj=JCTm)jk8|ZaaWD8nUOG3 zx|NB~w%x0s=^ID0D`>=_-(TwL!YDyPDf|OAN~6P-*isml5Bn;?`gAjThlV}ZnL2?KXlcq?6Dc`c?z-&Wsv}Q zb>aJBzVBoK7Z;?gw8aDFay{<;&$|kmLr`%Abu zNwT#>P~npqG%UdhVV&rw=Gb{C!tsRELSH3jtC}yr8`CfFn_Zh|h?5_=Iy(4ZVZckJ-W j2KY` z02GhJ*q|jGg_Uxee6^9N+qJFlLDV6xk5>{XaRDc?w$56wH>>IT^P4RyoSJ}76hv)V zakTVSK9u&IVJAVZUk$Y4Vh^8Pl-yc&?l?x(e4-F-MND9(P4n9~tN37_J3Q=a*RiwT zmRFhKKY{y>kNVi-k^D_$L=}kA2LMDvCy4g%%3_-SS1hdN%bQnHQ&TW9V&zBak~Z?l5Bk^a`|&!XFP9Bi{@wckk`9iJlscSD%Od6F zWNxz*>!l$l$(4v2)UAxNRM~zAAu~q1OKbOQ+A~JU@e}Jl8Zk!E4>mWF5AN!~tNaso x?7-xIr|X+{lQ?5{r)6(;NFR@kgI>R|gU}O=I|G4a&aztp?&uiaMBR84^gk<)h{gZ_ literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey3.png b/common/test/keyboards/obolo_chwerty_6351/source/welcome/chwertyftkey3.png new file mode 100644 index 0000000000000000000000000000000000000000..73d72a13d0de41ca3f90c102d2134c26a48ade6f GIT binary patch literal 8323 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 literal 0 HcmV?d00001 diff --git a/common/test/keyboards/obolo_chwerty_6351/source/welcome/welcome.htm b/common/test/keyboards/obolo_chwerty_6351/source/welcome/welcome.htm new file mode 100644 index 0000000000..625fd6ffd3 --- /dev/null +++ b/common/test/keyboards/obolo_chwerty_6351/source/welcome/welcome.htm @@ -0,0 +1,97 @@ + + + + + Start Using Obolo Chwerty Keyboard + + + + + +

+Obolo Chwerty Keyboard

+

Rogers Katelem Edeh


+ +

Onu! (Welcome!)

+

+This is the Chwerty layout for writing Obolo language. In this keyboard, accents are typed after the base letters. +

+So, to type "usem Obolo" with this keyboard layout, simply tap the given letters and tap the appropriate accents to pace them on the letters. +

+ + +

Keyboard Layout

+

+The keyboard uses CHWERTY layout. +

+"Ebi Obolo" do not have 'C' and 'H' in their "abiche" (alphabet), but they have the 'CH' sound (as well as the 'SH' sound in some dialect).
+This and other features make Obolo Language unique, hence this unique layout. +

+

Desktop Layout

+ + +

+ +

+

Mobile/Tablet Layout

+

Due to the size and number of keys, some characters are hidden in the long press. Press and hold on the key with a little dot on the top right to reveal and use them.

+

+ +

+ +

+ +

+ In this language, note that: +

(1) Only one tone mark can sit on a letter. So, diacritic stacking is not allowed. +

(2) Some tones are not to be marked in writing; they are not required. They are only used in primers and for beginners. +

(3) Some letters do not accept some accents. +

(4) Others do not accept accents at all. +

+Except for the optional accents which are not required, the keyboard will notify you when you inadvertently go against the spelling rules. +

+On mobile devices, tap the deadkey (⨷) then the given key to get the English letter in that position. +

+On desktop, if what you are doing does not support 'n̄' or does not render it well, then you can tap the BACKSLASH key after the 'n̄' to get 'ñ'. +

+The position of your BACKSLASH key depends on type of keyboard you are using. You can tell where your BACKSLASH key is by looking at the shape of the ENTER/RETURN key on your keyboard +

The three keyboard types and the respective position of the BACKSLASH keys are shown below: +

+ +

+ +

+ +

+Use this sentence to test your keyboard and character set: +

+mkpinyọn̄ kè evion̄ îben nchat balì ije bûu kire ǹnàan̄ iraka òsô mè ùkộ fiâm ikilap mudim m̀fọ̀tọ̀ shishini me èwê ozugbo +

+MKPINYỌN̄ KÈ EVION̄ ÎBEN NCHAT BALÌ IJE BÛU KIRE ǸNÀAN̄ IRAKA ÒSÔ MÈ ÙKỘ FIÂM IKILAP MUDIM M̀FỌ̀TỌ̀ SHISHINI ME ÈWÊ OZUGBO +

+Keyman ... type to the world in your language. +
+Obolo Chwerty ... ge inu me usem kwun̄ ria si ere geelek me linyọn̄. +

Onirọ-o! +

Itọn̄ ikup inyi Awaji! + + From f355722191719bc469f2ff945ea2b8881d57e89f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 10 Mar 2022 13:22:49 +1100 Subject: [PATCH 14/46] fix(web): back out caps lock and refix The Caps Lock change I made in the previous commit broke desktop Caps Lock handling. The fix was a little more convoluted. Turns out that _UpdateVKShift is also pretty crufty. I simplified it, removing dead code. --- .../src/text/keyboardProcessor.ts | 53 ++++++++----------- web/source/keymanweb.ts | 50 ++++++++--------- web/source/osk/browser/pendingMultiTap.ts | 2 + 3 files changed, 48 insertions(+), 57 deletions(-) diff --git a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts index dcd0d92e3b..59e15c6c5f 100644 --- a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts +++ b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts @@ -184,9 +184,9 @@ namespace com.keyman.text { setSyntheticEventDefaults(Lkc: text.KeyEvent) { // Set the flags for the state keys. - Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['CAPS'] ? 0 : Codes.modifierCodes['NO_CAPS']; - Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['NUM_LOCK'] ? 0 : Codes.modifierCodes['NO_NUM_LOCK']; - Lkc.Lstates |= Lkc.Lstates & Codes.modifierCodes['SCROLL_LOCK'] ? 0 : Codes.modifierCodes['NO_SCROLL_LOCK']; + Lkc.Lstates |= this.stateKeys['K_CAPS'] ? Codes.modifierCodes['CAPS'] : Codes.modifierCodes['NO_CAPS']; + Lkc.Lstates |= this.stateKeys['K_NUMLOCK'] ? Codes.modifierCodes['NUM_LOCK'] : Codes.modifierCodes['NO_NUM_LOCK']; + Lkc.Lstates |= this.stateKeys['K_SCROLL'] ? Codes.modifierCodes['SCROLL_LOCK'] : Codes.modifierCodes['NO_SCROLL_LOCK']; // Set LisVirtualKey to false to ensure that nomatch rule does fire for U_xxxx keys if(Lkc.kName && Lkc.kName.substr(0,2) == 'U_') { @@ -421,16 +421,14 @@ namespace com.keyman.text { * Function _UpdateVKShift * Scope Private * @param {Object} e OSK event - * @param {number} v keyboard shift state - * @param {(boolean|number)} d set (1) or clear(0) shift state bits * @return {boolean} Always true * Description Updates the current shift state within KMW, updating the OSK's visualization thereof. */ - _UpdateVKShift(e: KeyEvent, v: number, d: boolean|number): boolean { - var keyShiftState=0, lockStates=0, i; + _UpdateVKShift(e: KeyEvent): boolean { + let keyShiftState=0; - var lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK']; - var lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL']; + const lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK']; + const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL']; if(!this.activeKeyboard) { return true; @@ -439,7 +437,6 @@ namespace com.keyman.text { if(e) { // read shift states from Pevent keyShiftState = e.Lmodifiers; - lockStates = e.Lstates; // Are we simulating AltGr? If it's a simulation and not real, time to un-simulate for the OSK. if(this.activeKeyboard.isChiral && (this.activeKeyboard.emulatesAltGr) && @@ -448,25 +445,10 @@ namespace com.keyman.text { keyShiftState &= ~Codes.modifierCodes['RALT']; } - for(i=0; i < lockNames.length; i++) { - if(lockStates & Codes.stateBitmasks[lockNames[i]]) { - this.stateKeys[lockKeys[i]] = !!(lockStates & Codes.modifierCodes[lockNames[i]]); - } - } - } else if(d) { - keyShiftState |= v; - - for(i=0; i < lockNames.length; i++) { - if(v & Codes.stateBitmasks[lockNames[i]]) { - this.stateKeys[lockKeys[i]] = true; - } - } - } else { - keyShiftState &= ~v; - - for(i=0; i < lockNames.length; i++) { - if(v & Codes.stateBitmasks[lockNames[i]]) { - this.stateKeys[lockKeys[i]] = false; + // Set stateKeys where corresponding value is passed in e.Lstates + for(let i=0; i < lockNames.length; i++) { + if(e.Lstates & Codes.stateBitmasks[lockNames[i]]) { + this.stateKeys[lockKeys[i]] = !!(e.Lstates & Codes.modifierCodes[lockNames[i]]); } } } @@ -700,6 +682,13 @@ namespace com.keyman.text { this.layerId = 'default'; } + if(keyEvent.device.formFactor != utils.FormFactor.Desktop) { + // The caps layer works slightly differently on touch than on desktop. + // It's a single layer with no ability to mix with other modifiers + // We need to make sure that the state is kept in sync with the layer. + this.stateKeys['K_CAPS'] = this.layerId == 'caps'; + } + let baseModifierState = text.KeyboardProcessor.getModifierState(this.layerId); this.modStateFlags = baseModifierState | keyEvent.Lstates; } @@ -732,7 +721,7 @@ namespace com.keyman.text { // For eventual integration - we bypass an OSK update for physical keystrokes when in touch mode. this.activeKeyboard.notify(Levent.Lcode, outputTarget, isKeyDown ? 1 : 0); if(!Levent.device.touchable) { - return this._UpdateVKShift(Levent, Levent.Lcode-15, 1); // I2187 + return this._UpdateVKShift(Levent); // I2187 } else { return true; } @@ -740,7 +729,7 @@ namespace com.keyman.text { if(Levent.LmodifierChange) { this.activeKeyboard.notify(0, outputTarget, 1); - this._UpdateVKShift(Levent, 0, 1); + this._UpdateVKShift(Levent); } // No modifier keypresses detected. @@ -751,7 +740,7 @@ namespace com.keyman.text { this.layerId = 'default'; this.keyboardInterface.resetContextCache(); - this._UpdateVKShift(null, 15, 0); + this._UpdateVKShift(null); }; setNumericLayer(device: utils.DeviceSpec) { diff --git a/web/source/keymanweb.ts b/web/source/keymanweb.ts index f612438615..79aa71ac58 100644 --- a/web/source/keymanweb.ts +++ b/web/source/keymanweb.ts @@ -8,13 +8,13 @@ Copyright 2019 SIL International ***/ -// If KMW is already initialized, the KMW script has been loaded more than once. We wish to prevent resetting the +// If KMW is already initialized, the KMW script has been loaded more than once. We wish to prevent resetting the // KMW system, so we use the fact that 'initialized' is only 1 / true after all scripts are loaded for the initial // load of KMW. -if(!window['keyman']['initialized']) { +if(!window['keyman']['initialized']) { // Continued KeymanWeb initialization. - (function() + (function() { // Declare KeymanWeb, OnScreen Keyboard and Util object variables @@ -25,8 +25,8 @@ if(!window['keyman']['initialized']) { * Scope Private * @param {(string|Object)} s string (or object) to print * Description Simple debug display (upper right of screen) - * Extended to support multiple arguments May 2015 - */ + * Extended to support multiple arguments May 2015 + */ keymanweb['debug']=keymanweb.debug=function(s){ var p; if(keymanweb.debugElement == null) @@ -36,10 +36,10 @@ if(!window['keyman']['initialized']) { ds.minHeight='50px'; ds.border='1px solid blue'; ds.whiteSpace='pre-line';ds.overflowY='scroll'; p=document.createElement('P'); p.id='debug_output';p.style.margin='2px'; d.appendChild(p); - document.body.appendChild(d); - keymanweb.debugElement=p; - } - if((p=document.getElementById('debug_output')) == null) return; + document.body.appendChild(d); + keymanweb.debugElement=p; + } + if((p=document.getElementById('debug_output')) == null) return; if(arguments.length == 0) if(typeof p.textContent != 'undefined') p.textContent=''; else p.innerHTML=''; @@ -59,10 +59,10 @@ if(!window['keyman']['initialized']) { else { t1 = ''; - for(m in sx) + for(m in sx) { if(t1.length > 0) t1 = t1 + ', '; - t1 = t1 + m + ':'; + t1 = t1 + m + ':'; switch(typeof sx[m]) { case 'string': @@ -72,7 +72,7 @@ if(!window['keyman']['initialized']) { default: t1 = t1 + typeof sx[m]; break; } - if(t1.length > 1024) + if(t1.length > 1024) { t1 = t1.substr(0,1000)+'...'; break; } @@ -84,15 +84,15 @@ if(!window['keyman']['initialized']) { { t = t + sx; } - } + } // Truncate if necessary to avoid memory problems - if(t.length > 1500) t = t.substr(0,1500) + ' (more)'; - + if(t.length > 1500) t = t.substr(0,1500) + ' (more)'; + if(typeof p.textContent != 'undefined') p.textContent=t+'\n'+p.textContent; else p.innerHTML=t+'
'+p.innerHTML; - + } } @@ -102,28 +102,28 @@ if(!window['keyman']['initialized']) { */ keymanweb.debugElement=null; var dbg=keymanweb.debug; - + keymanweb.delayedInit(); //TODO: find all references to next three routines and disambiguate!! - + // Complete page initialization only after the page is fully loaded, including any embedded fonts // This avoids the need to use a timer to test for the fonts - + util.attachDOMEvent(window, 'load', keymanweb.domManager._WindowLoad,false); - util.attachDOMEvent(window, 'unload', keymanweb.domManager._WindowUnload,false); // added fourth argument (default value) - + util.attachDOMEvent(window, 'unload', keymanweb.domManager._WindowUnload,false); // added fourth argument (default value) + // *** I3319 Supplementary Plane modifications - end new code util.attachDOMEvent(document, 'keyup', keymanweb.hotkeyManager._Process, false); /** * Reset OSK shift states when entering or exiting the active element - **/ + **/ function resetVKShift() { let keyman = com.keyman.singleton; if(!keyman.uiManager.isActivating && keyman.osk.vkbd) { - keyman.core.keyboardProcessor._UpdateVKShift(null, 15, 0); //this should be enabled !!!!! TODO + keyman.core.keyboardProcessor._UpdateVKShift(null); //this should be enabled !!!!! TODO } } @@ -131,9 +131,9 @@ if(!window['keyman']['initialized']) { keymanweb['pageFocusHandler'] = resetVKShift; util.attachDOMEvent(window, 'focus', keymanweb['pageFocusHandler'], false); // I775 util.attachDOMEvent(window, 'blur', keymanweb['pageFocusHandler'], false); // I775 - + // Initialize supplementary plane string extensions - String.kmwEnableSupplementaryPlane(true); + String.kmwEnableSupplementaryPlane(true); })(); } \ No newline at end of file diff --git a/web/source/osk/browser/pendingMultiTap.ts b/web/source/osk/browser/pendingMultiTap.ts index 072ba0b412..5d11ac01f8 100644 --- a/web/source/osk/browser/pendingMultiTap.ts +++ b/web/source/osk/browser/pendingMultiTap.ts @@ -111,6 +111,8 @@ namespace com.keyman.osk { // description. let e = text.KeyEvent.constructNullKeyEvent(this.vkbd.device); e.kNextLayer = 'caps'; + e.Lstates = text.Codes.stateBitmasks.CAPS; + e.LmodifierChange = true; PreProcessor.raiseKeyEvent(e); } } From e1e82aacce124c0f69cfaf9d8946f44d78ffaefc Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 10 Mar 2022 13:33:21 +1100 Subject: [PATCH 15/46] fix(web): add test keyboards --- web/testing/commonHeader.js | 8 +- web/testing/obolo_chwerty.js | 3475 +++++++++++++++++++++++++++++++++ web/testing/test_chirality.js | 1 + web/testing/unminified.html | 2 +- 4 files changed, 3484 insertions(+), 2 deletions(-) create mode 100644 web/testing/obolo_chwerty.js create mode 100644 web/testing/test_chirality.js diff --git a/web/testing/commonHeader.js b/web/testing/commonHeader.js index 16ea1326fe..b9c3a27c39 100644 --- a/web/testing/commonHeader.js +++ b/web/testing/commonHeader.js @@ -93,7 +93,13 @@ doAddKeyboards({id:'web_context_tests',name:'Web Context Tests',languages:{id:'en',name:'English'}, filename:(prefix + 'web_context_tests.js')}); - // Add more keyboards to the language menu, by keyboard name, + doAddKeyboards({id:'test_chirality',name:'test_chirality',languages:{id:'en',name:'English'}, + filename:(prefix + 'test_chirality.js')}); + + doAddKeyboards({id:'obolo_chwerty',name:'obolo_chwerty',languages:{id:'en',name:'English'}, + filename:(prefix + 'obolo_chwerty.js')}); + + // Add more keyboards to the language menu, by keyboard name, // keyboard name and language code, or just the BCP-47 language code. // We use a different loading pattern here than in the samples version to provide a slightly different set of test cases. doAddKeyboards('french','@he'); diff --git a/web/testing/obolo_chwerty.js b/web/testing/obolo_chwerty.js new file mode 100644 index 0000000000..26b7ac59b3 --- /dev/null +++ b/web/testing/obolo_chwerty.js @@ -0,0 +1,3475 @@ +if(typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { +KeymanWeb.KR(new Keyboard_obolo_chwerty()); +} +function Keyboard_obolo_chwerty() +{ + var modCodes = keyman.osk.modifierCodes; + var keyCodes = keyman.osk.keyCodes; + + this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; + this.KI="Keyboard_obolo_chwerty"; + this.KN="Obolo Chwerty"; + this.KMINVER="15.0"; + this.KV={F:' 1em "Tahoma"',K102:1}; + this.KV.KLS={ + "default": ["`","1","2","3","4","5","6","7","8","9","0","-","=","","","","ch","w","e","r","t","y","u","i","o","p","[","]","\\ˆ","","","","a","s","d","f","g","sh","j","k","l",";","'","","","","","","","z","ọ","n̄","v","b","n","m",",",".","/","","","","","",""], + "shift": ["~´","!","@","#","$","%","₦","&","*","(",")","_","+","","","","CH","W","E","R","T","Y","U","I","O","P","{","}","|ˇ","","","","A","S","D","F","G","SH","J","K","L",":","\"","","","","","","","Z","Ọ","N̄","V","B","N","M","<",">","?","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KDU=0; + this.KH="A simple keyboard layout (chwerty) to help you type very easily in Obolo language."; + this.KM=0; + this.KBVER="1.2.1"; + this.KMBM=modCodes.SHIFT | modCodes.ALT | modCodes.CAPS | modCodes.NO_CAPS /* 0x0350 */; + this.KVKD="T_GRV T_ACU T_CCM T_CRN T_ENG T_Q T_H T_X T_C"; + this.KVKL={ + "tablet": { + "font": "Tahoma", + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "width": "111", + "id": "K_1", + "text": "1", + "sk": [ + { + "id": "U_00B9", + "text": "\u00B9" + }, + { + "id": "U_2081", + "text": "\u2081" + } + ] + }, + { + "width": "111", + "id": "K_2", + "text": "2", + "sk": [ + { + "id": "U_00B2", + "text": "\u00B2" + }, + { + "id": "U_2082" + } + ] + }, + { + "width": "111", + "id": "K_3", + "text": "3", + "sk": [ + { + "id": "U_00B3", + "text": "\u00B3" + }, + { + "id": "U_2083" + } + ] + }, + { + "width": "111", + "id": "K_4", + "text": "4", + "sk": [ + { + "id": "U_2074", + "text": "\u2074" + }, + { + "id": "U_2084", + "text": "\u2084" + } + ] + }, + { + "width": "111", + "id": "K_5", + "text": "5", + "sk": [ + { + "id": "U_2075", + "text": "\u2075" + }, + { + "id": "U_2085" + } + ] + }, + { + "width": "111", + "id": "K_6", + "text": "6", + "sk": [ + { + "id": "U_2076", + "text": "\u2076" + }, + { + "id": "U_2086" + } + ] + }, + { + "width": "111", + "id": "K_7", + "text": "7", + "sk": [ + { + "id": "U_2077", + "text": "\u2077" + }, + { + "id": "U_2087" + } + ] + }, + { + "width": "111", + "id": "K_8", + "text": "8", + "sk": [ + { + "id": "U_2078", + "text": "\u2078" + }, + { + "id": "U_2088", + "text": "\u2088" + } + ] + }, + { + "width": "111", + "id": "K_9", + "text": "9", + "sk": [ + { + "id": "U_2079", + "text": "\u2079" + }, + { + "id": "U_2089" + } + ] + }, + { + "width": "111", + "id": "K_0", + "text": "0", + "sk": [ + { + "id": "U_2070", + "text": "\u2070" + }, + { + "id": "U_2080" + } + ] + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "T_Q", + "text": "ch", + "sk": [ + { + "id": "U_0071", + "text": "q" + } + ] + }, + { + "id": "K_W", + "text": "w" + }, + { + "id": "K_E", + "text": "e", + "sk": [ + { + "id": "U_00E8", + "text": "\u00E8" + }, + { + "id": "U_00EA", + "text": "\u00EA" + } + ] + }, + { + "id": "K_R", + "text": "r" + }, + { + "id": "K_T", + "text": "t" + }, + { + "id": "K_Y", + "text": "y" + }, + { + "id": "K_U", + "text": "u", + "sk": [ + { + "id": "U_00F9", + "text": "\u00F9" + }, + { + "id": "U_00FB", + "text": "\u00FB" + } + ] + }, + { + "id": "K_I", + "text": "i", + "sk": [ + { + "id": "U_00EC", + "text": "\u00EC" + }, + { + "id": "U_00EE", + "text": "\u00EE" + } + ] + }, + { + "id": "K_O", + "text": "o", + "sk": [ + { + "id": "U_00F2", + "text": "\u00F2" + }, + { + "id": "U_00F4", + "text": "\u00F4" + } + ] + }, + { + "id": "K_P", + "text": "p" + }, + { + "id": "T_GRV", + "text": "\u02CB", + "sk": [ + { + "id": "T_ACU", + "text": "\u00B4" + } + ] + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_A", + "pad": "70", + "text": "a", + "sk": [ + { + "id": "U_00E0", + "text": "\u00E0" + }, + { + "id": "U_00E2", + "text": "\u00E2" + } + ] + }, + { + "id": "K_S", + "text": "s" + }, + { + "id": "K_D", + "text": "d" + }, + { + "id": "K_F", + "text": "f" + }, + { + "id": "K_G", + "text": "g" + }, + { + "id": "T_H", + "text": "sh", + "sk": [ + { + "id": "U_0068", + "text": "h" + }, + { + "id": "U_1E63", + "text": "\u1E63" + } + ] + }, + { + "id": "K_J", + "text": "j" + }, + { + "id": "K_K", + "text": "k" + }, + { + "id": "K_L", + "text": "l" + }, + { + "id": "T_CCM", + "text": "\u02C6", + "sk": [ + { + "id": "T_CRN", + "text": "\u02C7" + } + ] + }, + { + "width": "40", + "id": "T_SPA", + "sp": "10" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "shift", + "width": "120", + "id": "K_SHIFT", + "pad": "50", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "K_Z", + "text": "z" + }, + { + "id": "T_X", + "text": "\u1ECD", + "sk": [ + { + "id": "U_1ECD_0300", + "text": "\u1ECD\u0300" + }, + { + "id": "U_1ED9", + "text": "\u1ED9" + }, + { + "id": "U_0078", + "text": "x" + } + ] + }, + { + "id": "T_C", + "text": "n\u0304", + "sk": [ + { + "id": "U_00F1", + "text": "\u00F1" + }, + { + "id": "U_0063", + "text": "c" + } + ] + }, + { + "id": "K_V", + "text": "v" + }, + { + "id": "K_B", + "text": "b" + }, + { + "id": "K_N", + "text": "n", + "sk": [ + { + "id": "U_01F9", + "text": "\u01F9" + } + ] + }, + { + "id": "K_M", + "text": "m", + "sk": [ + { + "id": "U_006D_0300", + "text": "m\u0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_002F", + "text": "/" + }, + { + "id": "U_0027", + "text": "'" + }, + { + "id": "U_0022", + "text": "\"" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_003F", + "text": "?" + } + ] + }, + { + "width": "120", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + }, + { + "width": "20", + "id": "T_SPB", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "alt", + "width": "120", + "id": "K_ALT", + "sp": "1", + "text": "*Symbol*" + }, + { + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "K_COMMA", + "text": ",", + "sk": [ + { + "id": "U_003B", + "text": ";" + } + ] + }, + { + "width": "520", + "id": "K_SPACE" + }, + { + "id": "K_PERIOD", + "text": ".", + "sk": [ + { + "id": "U_003A", + "text": ":" + } + ] + }, + { + "id": "T_ENG", + "sp": "1", + "text": "\u2A37", + "sk": [ + { + "id": "U_2013", + "text": "\u2013" + }, + { + "id": "U_2014", + "text": "\u2014" + }, + { + "id": "U_005F", + "text": "_" + } + ] + }, + { + "width": "120", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": "1", + "key": [ + { + "width": "111", + "id": "K_1", + "text": "!" + }, + { + "width": "111", + "id": "K_2", + "text": "@" + }, + { + "width": "111", + "id": "K_3", + "text": "#" + }, + { + "width": "111", + "id": "K_4", + "text": "$" + }, + { + "width": "111", + "id": "K_5", + "text": "%", + "sk": [ + { + "id": "U_2030", + "text": "\u2030" + }, + { + "id": "U_2031", + "text": "\u2031" + } + ] + }, + { + "width": "111", + "id": "U_20A6", + "text": "\u20A6", + "sk": [ + { + "id": "U_005E", + "text": "^" + } + ] + }, + { + "width": "111", + "id": "K_7", + "text": "&" + }, + { + "width": "111", + "id": "K_8", + "text": "*" + }, + { + "width": "111", + "id": "K_9", + "text": "(" + }, + { + "width": "111", + "id": "K_0", + "text": ")" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "T_Q", + "text": "Ch", + "sk": [ + { + "id": "U_0051", + "text": "Q" + } + ] + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E", + "sk": [ + { + "id": "U_00C8", + "text": "\u00C8" + }, + { + "id": "U_00CA", + "text": "\u00CA" + } + ] + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U", + "sk": [ + { + "id": "U_00D9", + "text": "\u00D9" + }, + { + "id": "U_00DB", + "text": "\u00DB" + } + ] + }, + { + "id": "K_I", + "text": "I", + "sk": [ + { + "id": "U_00CC", + "text": "\u00CC" + }, + { + "id": "U_00CE", + "text": "\u00CE" + } + ] + }, + { + "id": "K_O", + "text": "O", + "sk": [ + { + "id": "U_00D2", + "text": "\u00D2" + }, + { + "id": "U_00D4", + "text": "\u00D4" + } + ] + }, + { + "id": "K_P", + "text": "P" + }, + { + "id": "T_GRV", + "text": "`", + "sk": [ + { + "id": "T_ACU", + "text": "\u00B4" + } + ] + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_A", + "pad": "70", + "text": "A", + "sk": [ + { + "id": "U_00C0", + "text": "\u00C0" + }, + { + "id": "U_00C2", + "text": "\u00C2" + } + ] + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "T_H", + "text": "Sh", + "sk": [ + { + "id": "U_0048", + "text": "H" + }, + { + "id": "U_1E62", + "text": "\u1E62" + } + ] + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "id": "T_CCM", + "text": "\u02C6", + "sk": [ + { + "id": "T_CRN", + "text": "\u02C7" + } + ] + }, + { + "width": "40", + "id": "T_SPC", + "sp": "10" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "default", + "width": "120", + "id": "K_SHIFT", + "pad": "50", + "sp": "2", + "text": "*Shift*" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "T_X", + "text": "\u1ECC", + "sk": [ + { + "id": "U_1ECC_0300", + "text": "\u1ECC\u0300" + }, + { + "id": "U_1ED8", + "text": "\u1ED8" + }, + { + "id": "U_0058", + "text": "X" + } + ] + }, + { + "id": "T_C", + "text": "N\u0304", + "sk": [ + { + "id": "U_00D1", + "text": "\u00D1" + }, + { + "id": "U_0043", + "text": "C" + } + ] + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N", + "sk": [ + { + "id": "U_01F8", + "text": "\u01F8" + } + ] + }, + { + "id": "K_M", + "text": "M", + "sk": [ + { + "id": "U_004D_0300", + "text": "M\u0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_002F", + "text": "/" + }, + { + "id": "U_0027", + "text": "'" + }, + { + "id": "U_0022", + "text": "\"" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_003F", + "text": "?" + } + ] + }, + { + "width": "120", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + }, + { + "width": "20", + "id": "T_SPD", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "alt", + "width": "120", + "id": "K_ALT", + "sp": "1", + "text": "*Symbol*" + }, + { + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "U_002C", + "text": ",", + "sk": [ + { + "id": "U_003B", + "text": ";" + } + ] + }, + { + "width": "520", + "id": "K_SPACE" + }, + { + "id": "U_002E", + "text": ".", + "sk": [ + { + "id": "U_003A", + "text": ":" + } + ] + }, + { + "id": "T_ENG", + "sp": "1", + "text": "\u2A37", + "sk": [ + { + "id": "U_2013", + "text": "\u2013" + }, + { + "id": "U_2014", + "text": "\u2014" + }, + { + "id": "U_005F", + "text": "_" + } + ] + }, + { + "width": "120", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "alt", + "row": [ + { + "id": "1", + "key": [ + { + "layer": "default", + "width": "111", + "id": "K_1", + "text": "1", + "sk": [ + { + "id": "U_00B9", + "text": "\u00B9" + }, + { + "id": "U_2081", + "text": "\u2081" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_2", + "text": "2", + "sk": [ + { + "id": "U_00B2", + "text": "\u00B2" + }, + { + "id": "U_2082", + "text": "\u2082" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_3", + "text": "3", + "sk": [ + { + "id": "U_00B3", + "text": "\u00B3" + }, + { + "id": "U_2083", + "text": "\u2083" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_4", + "text": "4", + "sk": [ + { + "id": "U_2074", + "text": "\u2074" + }, + { + "id": "U_2084", + "text": "\u2084" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_5", + "text": "5", + "sk": [ + { + "id": "U_2075", + "text": "\u2075" + }, + { + "id": "U_2085", + "text": "\u2085" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_6", + "text": "6", + "sk": [ + { + "id": "U_2076", + "text": "\u2076" + }, + { + "id": "U_2086", + "text": "\u2086" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_7", + "text": "7", + "sk": [ + { + "id": "U_2077", + "text": "\u2077" + }, + { + "id": "U_2087", + "text": "\u2087" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_8", + "text": "8", + "sk": [ + { + "id": "U_2078", + "text": "\u2078" + }, + { + "id": "U_2088", + "text": "\u2088" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_9", + "text": "9", + "sk": [ + { + "id": "U_2079", + "text": "\u2079" + }, + { + "id": "U_2089", + "text": "\u2089" + } + ] + }, + { + "layer": "default", + "width": "111", + "id": "K_0", + "text": "0", + "sk": [ + { + "id": "U_2070", + "text": "\u2070" + }, + { + "id": "U_2080", + "text": "\u2080" + } + ] + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "U_002B", + "text": "+", + "sk": [ + { + "id": "U_00B1", + "text": "\u00B1" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "id": "U_2213", + "text": "\u2213" + } + ] + }, + { + "id": "U_00D7", + "text": "\u00D7" + }, + { + "id": "U_00F7", + "text": "\u00F7" + }, + { + "id": "U_2236", + "text": "\u2236", + "sk": [ + { + "id": "U_00B7", + "text": "\u00B7" + }, + { + "id": "U_2234", + "text": "\u2234" + }, + { + "id": "U_2235", + "text": "\u2235" + } + ] + }, + { + "id": "U_221A", + "text": "\u221A", + "sk": [ + { + "id": "U_221B", + "text": "\u221B" + }, + { + "id": "U_221C", + "text": "\u221C" + } + ] + }, + { + "id": "U_005E", + "text": "^" + }, + { + "id": "U_003D", + "text": "=", + "sk": [ + { + "id": "U_2260", + "text": "\u2260" + }, + { + "id": "U_2248", + "text": "\u2248" + }, + { + "id": "U_2261", + "text": "\u2261" + } + ] + }, + { + "id": "U_007E", + "text": "~" + }, + { + "id": "U_203D", + "text": "\u203D", + "sk": [ + { + "id": "U_00A1", + "text": "\u00A1" + } + ] + }, + { + "id": "U_2713", + "text": "\u2713", + "sk": [ + { + "id": "U_0394", + "text": "\u0394" + }, + { + "id": "U_2717", + "text": "\u2717" + }, + { + "id": "U_26EF", + "text": "\u26EF" + }, + { + "id": "U_26ED", + "text": "\u26ED" + } + ] + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "U_007B", + "text": "{" + }, + { + "id": "U_00AB", + "text": "\u00AB" + }, + { + "id": "U_003C", + "text": "<", + "sk": [ + { + "id": "U_226A", + "text": "\u226A" + }, + { + "id": "U_2264", + "text": "\u2264" + } + ] + }, + { + "id": "U_005B", + "text": "[" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_007C", + "text": "|" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_005D", + "text": "]" + }, + { + "id": "U_003E", + "text": ">", + "sk": [ + { + "id": "U_226B", + "text": "\u226B" + }, + { + "id": "U_2265", + "text": "\u2265" + } + ] + }, + { + "id": "U_00BB", + "text": "\u00BB" + }, + { + "id": "U_007D", + "text": "}" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "shift", + "width": "120", + "id": "K_SHIFT", + "pad": "50", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "U_221E", + "text": "\u221E", + "sk": [ + { + "id": "U_2202", + "text": "\u2202" + } + ] + }, + { + "id": "U_222B", + "text": "\u222B", + "sk": [ + { + "id": "U_1E8B", + "text": "\u1E8B" + }, + { + "id": "U_1E8D", + "text": "\u1E8D" + }, + { + "id": "U_1E8F", + "text": "\u1E8F" + }, + { + "id": "U_04F1", + "text": "\u04F1" + } + ] + }, + { + "id": "U_00B0", + "text": "\u00B0", + "sk": [ + { + "id": "U_2103", + "text": "\u2103" + }, + { + "id": "U_2109", + "text": "\u2109" + } + ] + }, + { + "id": "U_03C0", + "text": "\u03C0" + }, + { + "id": "U_03B8", + "text": "\u03B8" + }, + { + "id": "U_33D1", + "text": "\u33D1", + "sk": [ + { + "id": "U_33D2", + "text": "\u33D2" + } + ] + }, + { + "id": "U_00A9", + "text": "\u00A9", + "sk": [ + { + "id": "U_00AE", + "text": "\u00AE" + }, + { + "id": "U_2117", + "text": "\u2117" + }, + { + "id": "U_1F6C8", + "text": "\uD83D\uDEC8" + }, + { + "id": "U_2122", + "text": "\u2122" + }, + { + "id": "U_2105", + "text": "\u2105" + } + ] + }, + { + "id": "U_002F", + "text": "/", + "sk": [ + { + "id": "U_005C", + "text": "\\" + } + ] + }, + { + "width": "120", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + }, + { + "width": "20", + "id": "T_SPF", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "default", + "width": "120", + "id": "K_ALT", + "sp": "1", + "text": "*abc*" + }, + { + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "U_00A7", + "text": "\u00A7", + "sk": [ + { + "id": "U_208D", + "text": "\u208D" + }, + { + "id": "U_2093", + "text": "\u2093" + }, + { + "id": "U_208A", + "text": "\u208A" + }, + { + "id": "U_208B", + "text": "\u208B" + }, + { + "id": "U_208E", + "text": "\u208E" + }, + { + "id": "U_208C", + "text": "\u208C" + } + ] + }, + { + "layer": "default", + "width": "520", + "id": "K_SPACE" + }, + { + "id": "U_00B6", + "text": "\u00B6", + "sk": [ + { + "id": "U_207D", + "text": "\u207D" + }, + { + "id": "U_207F", + "text": "\u207F" + }, + { + "id": "U_207A", + "text": "\u207A" + }, + { + "id": "U_207B", + "text": "\u207B" + }, + { + "id": "U_207E", + "text": "\u207E" + }, + { + "id": "U_207C", + "text": "\u207C" + } + ] + }, + { + "id": "U_03A9", + "sp": "1", + "text": "\u03A9", + "sk": [ + { + "id": "U_265A", + "text": "\u265A" + }, + { + "id": "U_2654", + "text": "\u2654" + }, + { + "id": "U_265B", + "text": "\u265B" + }, + { + "id": "U_2655", + "text": "\u2655" + }, + { + "id": "U_265D", + "text": "\u265D" + }, + { + "id": "U_2657", + "text": "\u2657" + }, + { + "id": "U_265C", + "text": "\u265C" + }, + { + "id": "U_2656", + "text": "\u2656" + }, + { + "id": "U_265E", + "text": "\u265E" + }, + { + "id": "U_2658", + "text": "\u2658" + }, + { + "id": "U_265F", + "text": "\u265F" + }, + { + "id": "U_2659", + "text": "\u2659" + } + ] + }, + { + "width": "120", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "caps", + "row": [ + { + "id": "1", + "key": [ + { + "width": "111", + "id": "K_1", + "text": "1" + }, + { + "width": "111", + "id": "K_2", + "text": "2" + }, + { + "width": "111", + "id": "K_3", + "text": "3" + }, + { + "width": "111", + "id": "K_4", + "text": "4" + }, + { + "width": "111", + "id": "K_5", + "text": "5" + }, + { + "width": "111", + "id": "K_6", + "text": "6" + }, + { + "width": "111", + "id": "K_7", + "text": "7" + }, + { + "width": "111", + "id": "K_8", + "text": "8" + }, + { + "width": "111", + "id": "K_9", + "text": "9" + }, + { + "width": "111", + "id": "K_0", + "text": "0" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "T_Q", + "text": "CH", + "sk": [ + { + "id": "U_0051", + "text": "Q" + } + ] + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E", + "sk": [ + { + "id": "U_00C8", + "text": "\u00C8" + }, + { + "id": "U_00CA", + "text": "\u00CA" + } + ] + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U", + "sk": [ + { + "id": "U_00D9", + "text": "\u00D9" + }, + { + "id": "U_00DB", + "text": "\u00DB" + } + ] + }, + { + "id": "K_I", + "text": "I", + "sk": [ + { + "id": "U_00CC", + "text": "\u00CC" + }, + { + "id": "U_00CE", + "text": "\u00CE" + } + ] + }, + { + "id": "K_O", + "text": "O", + "sk": [ + { + "id": "U_00D2", + "text": "\u00D2" + }, + { + "id": "U_00D4", + "text": "\u00D4" + } + ] + }, + { + "id": "K_P", + "text": "P" + }, + { + "id": "T_GRV", + "text": "`", + "sk": [ + { + "id": "T_ACU", + "text": "\u00B4" + } + ] + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_A", + "pad": "70", + "text": "A", + "sk": [ + { + "id": "U_00C0", + "text": "\u00C0" + }, + { + "id": "U_00C2", + "text": "\u00C2" + } + ] + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "T_H", + "text": "SH", + "sk": [ + { + "id": "U_0048", + "text": "H" + }, + { + "id": "U_1E62", + "text": "\u1E62" + } + ] + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "id": "T_CCM", + "text": "\u02C6", + "sk": [ + { + "id": "T_CRN", + "text": "\u02C7" + } + ] + }, + { + "width": "40", + "id": "T_SPC", + "sp": "10" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "default", + "width": "120", + "id": "K_SHIFT", + "pad": "50", + "sp": "2", + "text": "*Shift*" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "T_X", + "text": "\u1ECC", + "sk": [ + { + "id": "U_1ECC_0300", + "text": "\u1ECC\u0300" + }, + { + "id": "U_1ED8", + "text": "\u1ED8" + }, + { + "id": "U_0058", + "text": "X" + } + ] + }, + { + "id": "T_C", + "text": "N\u0304", + "sk": [ + { + "id": "U_00D1", + "text": "\u00D1" + }, + { + "id": "U_0043", + "text": "C" + } + ] + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N", + "sk": [ + { + "id": "U_01F8", + "text": "\u01F8" + } + ] + }, + { + "id": "K_M", + "text": "M", + "sk": [ + { + "id": "U_004D_0300", + "text": "M\u0300" + } + ] + }, + { + "id": "U_002D", + "text": "-", + "sk": [ + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_002F", + "text": "/" + }, + { + "id": "U_0027", + "text": "'" + }, + { + "id": "U_0022", + "text": "\"" + }, + { + "id": "U_0028", + "text": "(" + }, + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_003F", + "text": "?" + } + ] + }, + { + "width": "120", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + }, + { + "width": "20", + "id": "T_SPD", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "alt", + "width": "120", + "id": "K_ALT", + "sp": "1", + "text": "*Symbol*" + }, + { + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "U_002C", + "text": ",", + "sk": [ + { + "id": "U_003B", + "text": ";" + } + ] + }, + { + "width": "520", + "id": "K_SPACE" + }, + { + "id": "U_002E", + "text": ".", + "sk": [ + { + "id": "U_003A", + "text": ":" + } + ] + }, + { + "id": "T_ENG", + "sp": "1", + "text": "\u2A37", + "sk": [ + { + "id": "U_2013", + "text": "\u2013" + }, + { + "id": "U_2014", + "text": "\u2014" + }, + { + "id": "U_005F", + "text": "_" + } + ] + }, + { + "width": "120", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} +; + this.KCSS="/* tone keys colour */\n .android .kmw-keyboard-obolo_chwerty #default-T_GRV {color: #02ff02;}\n .android .kmw-keyboard-obolo_chwerty #default-T_CCM {color: #02ff02;}\n .android .kmw-keyboard-obolo_chwerty #shift-T_GRV {color: #02ff02;}\n .android .kmw-keyboard-obolo_chwerty #shift-T_CCM {color: #02ff02;}\n .android .kmw-keyboard-obolo_chwerty #caps-T_GRV {color: #02ff02;}\n .android .kmw-keyboard-obolo_chwerty #caps-T_CCM {color: #02ff02;}\n "; + this.s_digit_14="0123456789"; + this.s_sentencePunctuation_18=".?!‽"; + this.s_accentibles_19="aeiọoumnAEIỌOUMNn̄"; + this.s_accents_20=['','','','','','','','','','','','']; + this.s_nasals_21="mnMN"; + this.s_nnas_22=['','','','','','']; + this.s_vow_23="aeiouAEIOU"; + this.s_grave_24="àèìòùÀÈÌÒÙ"; + this.s_acute_25="áéíóúÁÉÍÓÚ"; + this.s_circum_26="âêîôûÂÊÎÔÛ"; + this.s_caron_27="ǎěǐǒǔǍĚǏǑǓ"; + this.s_acnasals_28="ḿńḾŃ"; + this.s_spguy_29="mnọMNỌ"; + this.s_spguyop_30="ḿǹộḾǸỘ"; + this.s_erase_31=['','','','']; + this.s_gravekeys_32=['','','','']; + this.s_acutekeys_33=['','','','']; + this.s_circumflexkeys_34=['','','','']; + this.s_caronkeys_35=['','','','']; + this.s41="0"; + this.s42="numeric"; + this.s43="caps"; + this.s44="0"; + this.s45="shift"; + this.s46="shift"; + this.s47="shift"; + this.s48="default"; + this.KVER="15.0.204.0"; + this.KVS=[]; + this.gs=function(t,e) { + return this.g_main_3(t,e); + }; + this.gn=function(t,e) { + return this.g_NewContext_0(t,e); + }; + this.gpk=function(t,e) { + return this.g_PostKeystroke_1(t,e); + }; + this.gs=function(t,e) { + return this.g_main_3(t,e); + }; + this.g_NewContext_0=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(!m) { + + k.KDC(-1,t); + r=this.g_detectStartOfSentence_2(t,e); + m=2; + } + return r; + }; + this.g_PostKeystroke_1=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KFCM(1,t,[{t:'a',a:this.s_digit_14}])&&k.KIFS(42,this.s41,t)&&k.KIFS(33,this.s42,t)){ + m=1; // Line 24 + k.KDC(1,t); + k.KIO(-1,this.s_digit_14,1,t); + } + else if(k.KIFS(33,this.s43,t)){ + m=1; // Line 25 + k.KDC(0,t); + } + else if(k.KIFS(42,this.s44,t)){ + m=1; // Line 26 + k.KDC(0,t); + r=this.g_detectStartOfSentence_2(t,e); + m=2; + } + return r; + }; + this.g_detectStartOfSentence_2=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KFCM(3,t,[{t:'a',a:this.s_sentencePunctuation_18},' ',' '])){ + m=1; // Line 31 + k.KDC(3,t); + k.KIO(-1,this.s_sentencePunctuation_18,1,t); + k.KO(-1,t," "); + k.KSETS(33,this.s47,t); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_sentencePunctuation_18},' '])){ + m=1; // Line 30 + k.KDC(2,t); + k.KIO(-1,this.s_sentencePunctuation_18,1,t); + k.KO(-1,t," "); + k.KSETS(33,this.s46,t); + } + else if(k.KFCM(1,t,[{t:'n'}])){ + m=1; // Line 29 + k.KDC(0,t); + k.KSETS(33,this.s45,t); + } + if(!m) { + + k.KDC(-1,t); + k.KSETS(33,this.s48,t); + } + return r; + }; + this.g_main_3=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(2,t,['c','h'])){ + r=m=1; // Line 237 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','h'])){ + r=m=1; // Line 238 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','H'])){ + r=m=1; // Line 239 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['s','h'])){ + r=m=1; // Line 240 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','h'])){ + r=m=1; // Line 241 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','H'])){ + r=m=1; // Line 242 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['n','̄'])){ + r=m=1; // Line 243 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['N','̄'])){ + r=m=1; // Line 244 + k.KDC(2,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_grave_24}])){ + r=m=1; // Line 247 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_acute_25}])){ + r=m=1; // Line 248 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_circum_26}])){ + r=m=1; // Line 249 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_caron_27}])){ + r=m=1; // Line 250 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_spguyop_30}])){ + r=m=1; // Line 251 + k.KDC(1,t); + k.KIO(-1,this.s_spguy_29,1,t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(2,t,['c','h'])){ + r=m=1; // Line 237 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','h'])){ + r=m=1; // Line 238 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','H'])){ + r=m=1; // Line 239 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['s','h'])){ + r=m=1; // Line 240 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','h'])){ + r=m=1; // Line 241 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','H'])){ + r=m=1; // Line 242 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['n','̄'])){ + r=m=1; // Line 243 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['N','̄'])){ + r=m=1; // Line 244 + k.KDC(2,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_grave_24}])){ + r=m=1; // Line 247 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_acute_25}])){ + r=m=1; // Line 248 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_circum_26}])){ + r=m=1; // Line 249 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_caron_27}])){ + r=m=1; // Line 250 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_spguyop_30}])){ + r=m=1; // Line 251 + k.KDC(1,t); + k.KIO(-1,this.s_spguy_29,1,t); + } + } + else if(k.KKM(e, modCodes.ALT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4240 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(2,t,['c','h'])){ + r=m=1; // Line 237 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','h'])){ + r=m=1; // Line 238 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','H'])){ + r=m=1; // Line 239 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['s','h'])){ + r=m=1; // Line 240 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','h'])){ + r=m=1; // Line 241 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','H'])){ + r=m=1; // Line 242 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['n','̄'])){ + r=m=1; // Line 243 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['N','̄'])){ + r=m=1; // Line 244 + k.KDC(2,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_grave_24}])){ + r=m=1; // Line 247 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_acute_25}])){ + r=m=1; // Line 248 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_circum_26}])){ + r=m=1; // Line 249 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_caron_27}])){ + r=m=1; // Line 250 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_spguyop_30}])){ + r=m=1; // Line 251 + k.KDC(1,t); + k.KIO(-1,this.s_spguy_29,1,t); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(2,t,['c','h'])){ + r=m=1; // Line 237 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','h'])){ + r=m=1; // Line 238 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['C','H'])){ + r=m=1; // Line 239 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['s','h'])){ + r=m=1; // Line 240 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','h'])){ + r=m=1; // Line 241 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['S','H'])){ + r=m=1; // Line 242 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['n','̄'])){ + r=m=1; // Line 243 + k.KDC(2,t); + } + else if(k.KFCM(2,t,['N','̄'])){ + r=m=1; // Line 244 + k.KDC(2,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_grave_24}])){ + r=m=1; // Line 247 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_acute_25}])){ + r=m=1; // Line 248 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_circum_26}])){ + r=m=1; // Line 249 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_caron_27}])){ + r=m=1; // Line 250 + k.KDC(1,t); + k.KIO(-1,this.s_vow_23,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_spguyop_30}])){ + r=m=1; // Line 251 + k.KDC(1,t); + k.KIO(-1,this.s_spguy_29,1,t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x105)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 163 + k.KDC(1,t); + k.KO(-1,t,"q"); + } + else if(1){ + r=m=1; // Line 109 + k.KDC(0,t); + k.KO(-1,t,"ch"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x105)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 164 + k.KDC(1,t); + k.KO(-1,t,"Q"); + } + else if(1){ + r=m=1; // Line 110 + k.KDC(0,t); + k.KO(-1,t,"Ch"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x105)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 165 + k.KDC(1,t); + k.KO(-1,t,"Q"); + } + else if(1){ + r=m=1; // Line 111 + k.KDC(0,t); + k.KO(-1,t,"CH"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x106)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 167 + k.KDC(1,t); + k.KO(-1,t,"h"); + } + else if(1){ + r=m=1; // Line 113 + k.KDC(0,t); + k.KO(-1,t,"sh"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x106)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 168 + k.KDC(1,t); + k.KO(-1,t,"H"); + } + else if(1){ + r=m=1; // Line 114 + k.KDC(0,t); + k.KO(-1,t,"Sh"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x106)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 169 + k.KDC(1,t); + k.KO(-1,t,"H"); + } + else if(1){ + r=m=1; // Line 115 + k.KDC(0,t); + k.KO(-1,t,"SH"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x107)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 171 + k.KDC(1,t); + k.KO(-1,t,"x"); + } + else if(1){ + r=m=1; // Line 117 + k.KDC(0,t); + k.KO(-1,t,"ọ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x107)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 172 + k.KDC(1,t); + k.KO(-1,t,"X"); + } + else if(1){ + r=m=1; // Line 118 + k.KDC(0,t); + k.KO(-1,t,"Ọ"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x107)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 173 + k.KDC(1,t); + k.KO(-1,t,"X"); + } + else if(1){ + r=m=1; // Line 119 + k.KDC(0,t); + k.KO(-1,t,"Ọ"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x108)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 175 + k.KDC(1,t); + k.KO(-1,t,"c"); + } + else if(1){ + r=m=1; // Line 121 + k.KDC(0,t); + k.KO(-1,t,"n̄"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x108)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 176 + k.KDC(1,t); + k.KO(-1,t,"C"); + } + else if(1){ + r=m=1; // Line 122 + k.KDC(0,t); + k.KO(-1,t,"N̄"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x108)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 177 + k.KDC(1,t); + k.KO(-1,t,"C"); + } + else if(1){ + r=m=1; // Line 123 + k.KDC(0,t); + k.KO(-1,t,"N̄"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x100)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 184 + k.KDC(1,t); + k.KO(-1,t,"`"); + } + else if(k.KFCM(1,t,['m'])){ + r=m=1; // Line 205 + k.KDC(1,t); + k.KO(-1,t,"m̀"); + } + else if(k.KFCM(1,t,['M'])){ + r=m=1; // Line 206 + k.KDC(1,t); + k.KO(-1,t,"M̀"); + } + else if(k.KFCM(1,t,['n'])){ + r=m=1; // Line 208 + k.KDC(1,t); + k.KO(-1,t,"ǹ"); + } + else if(k.KFCM(1,t,['N'])){ + r=m=1; // Line 209 + k.KDC(1,t); + k.KO(-1,t,"Ǹ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 211 + k.KDC(1,t); + k.KO(-1,t,"ọ̀"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 212 + k.KDC(1,t); + k.KO(-1,t,"Ọ̀"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 230 + k.KDC(1,t); + k.KIO(-1,this.s_grave_24,1,t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x100)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 185 + k.KDC(1,t); + k.KO(-1,t,"`"); + } + else if(k.KFCM(1,t,['m'])){ + r=m=1; // Line 205 + k.KDC(1,t); + k.KO(-1,t,"m̀"); + } + else if(k.KFCM(1,t,['M'])){ + r=m=1; // Line 206 + k.KDC(1,t); + k.KO(-1,t,"M̀"); + } + else if(k.KFCM(1,t,['n'])){ + r=m=1; // Line 208 + k.KDC(1,t); + k.KO(-1,t,"ǹ"); + } + else if(k.KFCM(1,t,['N'])){ + r=m=1; // Line 209 + k.KDC(1,t); + k.KO(-1,t,"Ǹ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 211 + k.KDC(1,t); + k.KO(-1,t,"ọ̀"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 212 + k.KDC(1,t); + k.KO(-1,t,"Ọ̀"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 230 + k.KDC(1,t); + k.KIO(-1,this.s_grave_24,1,t); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x100)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 186 + k.KDC(1,t); + k.KO(-1,t,"`"); + } + else if(k.KFCM(1,t,['m'])){ + r=m=1; // Line 205 + k.KDC(1,t); + k.KO(-1,t,"m̀"); + } + else if(k.KFCM(1,t,['M'])){ + r=m=1; // Line 206 + k.KDC(1,t); + k.KO(-1,t,"M̀"); + } + else if(k.KFCM(1,t,['n'])){ + r=m=1; // Line 208 + k.KDC(1,t); + k.KO(-1,t,"ǹ"); + } + else if(k.KFCM(1,t,['N'])){ + r=m=1; // Line 209 + k.KDC(1,t); + k.KO(-1,t,"Ǹ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 211 + k.KDC(1,t); + k.KO(-1,t,"ọ̀"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 212 + k.KDC(1,t); + k.KO(-1,t,"Ọ̀"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 230 + k.KDC(1,t); + k.KIO(-1,this.s_grave_24,1,t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x101)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 188 + k.KDC(1,t); + k.KO(-1,t,"´"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 214 + k.KDC(1,t); + k.KO(-1,t,"ọ́"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KO(-1,t,"Ọ́"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 231 + k.KDC(1,t); + k.KIO(-1,this.s_acute_25,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 234 + k.KDC(1,t); + k.KIO(-1,this.s_acnasals_28,1,t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x101)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 189 + k.KDC(1,t); + k.KO(-1,t,"´"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 214 + k.KDC(1,t); + k.KO(-1,t,"ọ́"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KO(-1,t,"Ọ́"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 231 + k.KDC(1,t); + k.KIO(-1,this.s_acute_25,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 234 + k.KDC(1,t); + k.KIO(-1,this.s_acnasals_28,1,t); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x101)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 190 + k.KDC(1,t); + k.KO(-1,t,"´"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 214 + k.KDC(1,t); + k.KO(-1,t,"ọ́"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KO(-1,t,"Ọ́"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 231 + k.KDC(1,t); + k.KIO(-1,this.s_acute_25,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 234 + k.KDC(1,t); + k.KIO(-1,this.s_acnasals_28,1,t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x102)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 192 + k.KDC(1,t); + k.KO(-1,t,"ˆ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 217 + k.KDC(1,t); + k.KO(-1,t,"ộ"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 218 + k.KDC(1,t); + k.KO(-1,t,"Ộ"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 232 + k.KDC(1,t); + k.KIO(-1,this.s_circum_26,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x102)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 193 + k.KDC(1,t); + k.KO(-1,t,"ˆ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 217 + k.KDC(1,t); + k.KO(-1,t,"ộ"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 218 + k.KDC(1,t); + k.KO(-1,t,"Ộ"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 232 + k.KDC(1,t); + k.KIO(-1,this.s_circum_26,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x102)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 194 + k.KDC(1,t); + k.KO(-1,t,"ˆ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 217 + k.KDC(1,t); + k.KO(-1,t,"ộ"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 218 + k.KDC(1,t); + k.KO(-1,t,"Ộ"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 232 + k.KDC(1,t); + k.KIO(-1,this.s_circum_26,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x103)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 196 + k.KDC(1,t); + k.KO(-1,t,"ˇ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 220 + k.KDC(1,t); + k.KO(-1,t,"ọ̌"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 221 + k.KDC(1,t); + k.KO(-1,t,"Ọ̌"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 233 + k.KDC(1,t); + k.KIO(-1,this.s_caron_27,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x103)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 197 + k.KDC(1,t); + k.KO(-1,t,"ˇ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 220 + k.KDC(1,t); + k.KO(-1,t,"ọ̌"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 221 + k.KDC(1,t); + k.KO(-1,t,"Ọ̌"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 233 + k.KDC(1,t); + k.KIO(-1,this.s_caron_27,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x103)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 198 + k.KDC(1,t); + k.KO(-1,t,"ˇ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 220 + k.KDC(1,t); + k.KO(-1,t,"ọ̌"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 221 + k.KDC(1,t); + k.KO(-1,t,"Ọ̌"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 233 + k.KDC(1,t); + k.KIO(-1,this.s_caron_27,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 253 + k.KDC(1,t); + k.KIO(-1,this.s_nasals_21,1,t); + k.KB(t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, 0x104)) { + if(1){ + r=m=1; // Line 58 + k.KDC(0,t); + k.KDO(-1,t,0); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, 0x104)) { + if(1){ + r=m=1; // Line 59 + k.KDC(0,t); + k.KDO(-1,t,1); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, 0x104)) { + if(1){ + r=m=1; // Line 60 + k.KDC(0,t); + k.KDO(-1,t,2); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 200 + k.KDC(1,t); + k.KO(-1,t,"¯"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 202 + k.KDC(1,t); + k.KO(-1,t,"¯"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_A /* 0x41 */)) { + if(1){ + r=m=1; // Line 63 + k.KDC(0,t); + k.KO(-1,t,"A"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_B /* 0x42 */)) { + if(1){ + r=m=1; // Line 64 + k.KDC(0,t); + k.KO(-1,t,"B"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_C /* 0x43 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 133 + k.KDC(1,t); + k.KO(-1,t,"C"); + } + else if(1){ + r=m=1; // Line 89 + k.KDC(0,t); + k.KO(-1,t,"N̄"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_C /* 0x43 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 135 + k.KDC(1,t); + k.KO(-1,t,"C"); + } + else if(1){ + r=m=1; // Line 104 + k.KDC(0,t); + k.KO(-1,t,"N̄"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_D /* 0x44 */)) { + if(1){ + r=m=1; // Line 65 + k.KDC(0,t); + k.KO(-1,t,"D"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_E /* 0x45 */)) { + if(1){ + r=m=1; // Line 66 + k.KDC(0,t); + k.KO(-1,t,"E"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_F /* 0x46 */)) { + if(1){ + r=m=1; // Line 67 + k.KDC(0,t); + k.KO(-1,t,"F"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_G /* 0x47 */)) { + if(1){ + r=m=1; // Line 68 + k.KDC(0,t); + k.KO(-1,t,"G"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_H /* 0x48 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 143 + k.KDC(1,t); + k.KO(-1,t,"H"); + } + else if(1){ + r=m=1; // Line 87 + k.KDC(0,t); + k.KO(-1,t,"SH"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_H /* 0x48 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 145 + k.KDC(1,t); + k.KO(-1,t,"H"); + } + else if(1){ + r=m=1; // Line 102 + k.KDC(0,t); + k.KO(-1,t,"Sh"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_I /* 0x49 */)) { + if(1){ + r=m=1; // Line 69 + k.KDC(0,t); + k.KO(-1,t,"I"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_J /* 0x4A */)) { + if(1){ + r=m=1; // Line 70 + k.KDC(0,t); + k.KO(-1,t,"J"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_K /* 0x4B */)) { + if(1){ + r=m=1; // Line 71 + k.KDC(0,t); + k.KO(-1,t,"K"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_L /* 0x4C */)) { + if(1){ + r=m=1; // Line 72 + k.KDC(0,t); + k.KO(-1,t,"L"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_M /* 0x4D */)) { + if(1){ + r=m=1; // Line 73 + k.KDC(0,t); + k.KO(-1,t,"M"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_N /* 0x4E */)) { + if(1){ + r=m=1; // Line 74 + k.KDC(0,t); + k.KO(-1,t,"N"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_O /* 0x4F */)) { + if(1){ + r=m=1; // Line 75 + k.KDC(0,t); + k.KO(-1,t,"O"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_P /* 0x50 */)) { + if(1){ + r=m=1; // Line 76 + k.KDC(0,t); + k.KO(-1,t,"P"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_Q /* 0x51 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 148 + k.KDC(1,t); + k.KO(-1,t,"Q"); + } + else if(1){ + r=m=1; // Line 86 + k.KDC(0,t); + k.KO(-1,t,"CH"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_Q /* 0x51 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 150 + k.KDC(1,t); + k.KO(-1,t,"Q"); + } + else if(1){ + r=m=1; // Line 101 + k.KDC(0,t); + k.KO(-1,t,"Ch"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_R /* 0x52 */)) { + if(1){ + r=m=1; // Line 77 + k.KDC(0,t); + k.KO(-1,t,"R"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_S /* 0x53 */)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 180 + k.KDC(1,t); + k.KO(-1,t,"Ṣ"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_S /* 0x53 */)) { + if(k.KFCM(1,t,[{t:'d',d:2}])){ + r=m=1; // Line 181 + k.KDC(1,t); + k.KO(-1,t,"Ṣ"); + } + else if(1){ + r=m=1; // Line 78 + k.KDC(0,t); + k.KO(-1,t,"S"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 79 + k.KDC(0,t); + k.KO(-1,t,"T"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_U /* 0x55 */)) { + if(1){ + r=m=1; // Line 80 + k.KDC(0,t); + k.KO(-1,t,"U"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_V /* 0x56 */)) { + if(1){ + r=m=1; // Line 81 + k.KDC(0,t); + k.KO(-1,t,"V"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_W /* 0x57 */)) { + if(1){ + r=m=1; // Line 82 + k.KDC(0,t); + k.KO(-1,t,"W"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_X /* 0x58 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 138 + k.KDC(1,t); + k.KO(-1,t,"X"); + } + else if(1){ + r=m=1; // Line 88 + k.KDC(0,t); + k.KO(-1,t,"Ọ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_X /* 0x58 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 140 + k.KDC(1,t); + k.KO(-1,t,"X"); + } + else if(1){ + r=m=1; // Line 103 + k.KDC(0,t); + k.KO(-1,t,"Ọ"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_Y /* 0x59 */)) { + if(1){ + r=m=1; // Line 83 + k.KDC(0,t); + k.KO(-1,t,"Y"); + } + } + else if(k.KKM(e, modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4100 */, keyCodes.K_Z /* 0x5A */)) { + if(1){ + r=m=1; // Line 84 + k.KDC(0,t); + k.KO(-1,t,"Z"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSLASH /* 0xDC */)) { + if(k.KFCM(2,t,['n','̄'])){ + r=m=1; // Line 223 + k.KDC(2,t); + k.KO(-1,t,"ñ"); + } + else if(k.KFCM(2,t,['N','̄'])){ + r=m=1; // Line 224 + k.KDC(2,t); + k.KO(-1,t,"Ñ"); + } + else if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 159 + k.KDC(1,t); + k.KO(-1,t,"ˆ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 217 + k.KDC(1,t); + k.KO(-1,t,"ộ"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 218 + k.KDC(1,t); + k.KO(-1,t,"Ộ"); + } + else if(k.KFCM(1,t,['s'])){ + r=m=1; // Line 226 + k.KDC(1,t); + k.KO(-1,t,"ṣ"); + } + else if(k.KFCM(1,t,['S'])){ + r=m=1; // Line 227 + k.KDC(1,t); + k.KO(-1,t,"Ṣ"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 232 + k.KDC(1,t); + k.KIO(-1,this.s_circum_26,1,t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_6 /* 0x36 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 153 + k.KDC(1,t); + k.KO(-1,t,"^"); + } + else if(1){ + r=m=1; // Line 106 + k.KDC(0,t); + k.KO(-1,t,"₦"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4210 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(k.KFCM(1,t,[{t:'d',d:1}])){ + r=m=1; // Line 201 + k.KDC(1,t); + k.KO(-1,t,"¯"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 156 + k.KDC(1,t); + k.KO(-1,t,"`"); + } + else if(k.KFCM(1,t,['m'])){ + r=m=1; // Line 205 + k.KDC(1,t); + k.KO(-1,t,"m̀"); + } + else if(k.KFCM(1,t,['M'])){ + r=m=1; // Line 206 + k.KDC(1,t); + k.KO(-1,t,"M̀"); + } + else if(k.KFCM(1,t,['n'])){ + r=m=1; // Line 208 + k.KDC(1,t); + k.KO(-1,t,"ǹ"); + } + else if(k.KFCM(1,t,['N'])){ + r=m=1; // Line 209 + k.KDC(1,t); + k.KO(-1,t,"Ǹ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 211 + k.KDC(1,t); + k.KO(-1,t,"ọ̀"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 212 + k.KDC(1,t); + k.KO(-1,t,"Ọ̀"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 230 + k.KDC(1,t); + k.KIO(-1,this.s_grave_24,1,t); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_C /* 0x43 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 134 + k.KDC(1,t); + k.KO(-1,t,"c"); + } + else if(1){ + r=m=1; // Line 94 + k.KDC(0,t); + k.KO(-1,t,"n̄"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 */, keyCodes.K_C /* 0x43 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 136 + k.KDC(1,t); + k.KO(-1,t,"c"); + } + else if(1){ + r=m=1; // Line 99 + k.KDC(0,t); + k.KO(-1,t,"n̄"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_H /* 0x48 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 144 + k.KDC(1,t); + k.KO(-1,t,"h"); + } + else if(1){ + r=m=1; // Line 92 + k.KDC(0,t); + k.KO(-1,t,"sh"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 */, keyCodes.K_H /* 0x48 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 146 + k.KDC(1,t); + k.KO(-1,t,"h"); + } + else if(1){ + r=m=1; // Line 97 + k.KDC(0,t); + k.KO(-1,t,"Sh"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_Q /* 0x51 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 149 + k.KDC(1,t); + k.KO(-1,t,"q"); + } + else if(1){ + r=m=1; // Line 91 + k.KDC(0,t); + k.KO(-1,t,"ch"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 */, keyCodes.K_Q /* 0x51 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 151 + k.KDC(1,t); + k.KO(-1,t,"q"); + } + else if(1){ + r=m=1; // Line 96 + k.KDC(0,t); + k.KO(-1,t,"Ch"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_S /* 0x53 */)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 179 + k.KDC(1,t); + k.KO(-1,t,"ṣ"); + } + } + else if(k.KKM(e, modCodes.NO_CAPS | modCodes.VIRTUAL_KEY /* 0x4200 */, keyCodes.K_X /* 0x58 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 139 + k.KDC(1,t); + k.KO(-1,t,"x"); + } + else if(1){ + r=m=1; // Line 93 + k.KDC(0,t); + k.KO(-1,t,"ọ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 */, keyCodes.K_X /* 0x58 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 141 + k.KDC(1,t); + k.KO(-1,t,"x"); + } + else if(1){ + r=m=1; // Line 98 + k.KDC(0,t); + k.KO(-1,t,"ọ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKSLASH /* 0xDC */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 160 + k.KDC(1,t); + k.KO(-1,t,"ˇ"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 220 + k.KDC(1,t); + k.KO(-1,t,"ọ̌"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 221 + k.KDC(1,t); + k.KO(-1,t,"Ọ̌"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 233 + k.KDC(1,t); + k.KIO(-1,this.s_caron_27,1,t); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(k.KFCM(1,t,[']'])){ + r=m=1; // Line 157 + k.KDC(1,t); + k.KO(-1,t,"´"); + } + else if(k.KFCM(1,t,['ọ'])){ + r=m=1; // Line 214 + k.KDC(1,t); + k.KO(-1,t,"ọ́"); + } + else if(k.KFCM(1,t,['Ọ'])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KO(-1,t,"Ọ́"); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_vow_23}])){ + r=m=1; // Line 231 + k.KDC(1,t); + k.KIO(-1,this.s_acute_25,1,t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_nasals_21}])){ + r=m=1; // Line 234 + k.KDC(1,t); + k.KIO(-1,this.s_acnasals_28,1,t); + } + } + return r; + }; +} diff --git a/web/testing/test_chirality.js b/web/testing/test_chirality.js new file mode 100644 index 0000000000..1011b551b3 --- /dev/null +++ b/web/testing/test_chirality.js @@ -0,0 +1 @@ +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_test_chirality());}function Keyboard_test_chirality(){this.KI="Keyboard_test_chirality";this.KN="KeymanWeb Chirality Tester";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KDU=1;this.KV.KLS={};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x031F;this.KVER="10.0.1057.0";this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16658,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RC_CAP_a");}else if(k.KKM(e,16666,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RCA_CAP_a");}else if(k.KKM(e,16664,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RA_CAP_a");}else if(k.KKM(e,16657,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_CAP_a");}else if(k.KKM(e,16660,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_CAP_a");}else if(k.KKM(e,16642,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RC_a");}else if(k.KKM(e,16650,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RCA_a");}else if(k.KKM(e,16648,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_RA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16645,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LCA_a");}else if(k.KKM(e,16644,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LA_a");}else if(k.KKM(e,16641,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_LC_a");}else if(k.KKM(e,16914,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RC_CAP_a");}else if(k.KKM(e,16922,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RCA_CAP_a");}else if(k.KKM(e,16920,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RA_CAP_a");}else if(k.KKM(e,16913,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_CAP_a");}else if(k.KKM(e,16916,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_CAP_a");}else if(k.KKM(e,16898,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RC_a");}else if(k.KKM(e,16906,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RCA_a");}else if(k.KKM(e,16904,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"RA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_a");}else if(k.KKM(e,16901,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LCA_a");}else if(k.KKM(e,16900,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LA_a");}else if(k.KKM(e,16897,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"LC_a");}else if(k.KKM(e,16640,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_DF_a");}else if(k.KKM(e,16912,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"DF_CAP_a");}else if(k.KKM(e,16656,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"CAPSLOCK_DF_CAP_a");}else if(k.KKM(e,16896,65)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"DF_a");}else if(k.KKM(e,16384,66)) {r=m=1;k.KDC(0,t);k.KO(-1,t,"b");}return r;};} \ No newline at end of file diff --git a/web/testing/unminified.html b/web/testing/unminified.html index 4f1a28c731..c4aad22dd5 100644 --- a/web/testing/unminified.html +++ b/web/testing/unminified.html @@ -18,7 +18,7 @@ From b213c3b8291221746d96013769308430d7716f04 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 10 Mar 2022 13:15:59 +0700 Subject: [PATCH 16/46] fix(android/engine): Test fileVersion during package install --- .../tavultesoft/kmapro/PackageActivity.java | 7 ++++ .../kMAPro/src/main/res/values/strings.xml | 3 ++ .../kmea/packages/PackageProcessor.java | 16 +++++++++ common/test/keyboards/the_99/README.md | 34 ++++++++++++++++++ common/test/keyboards/the_99/the_99.kmp | Bin 0 -> 3770 bytes 5 files changed, 60 insertions(+) create mode 100644 common/test/keyboards/the_99/README.md create mode 100644 common/test/keyboards/the_99/the_99.kmp diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java index d18075ce42..1ae612a93a 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java @@ -105,6 +105,13 @@ public class PackageActivity extends AppCompatActivity implements return; } + // Check minimum keyboard version to ensure current version of Keyman supports the features + String pkgMinimumKeyboardVersion = kmpProcessor.getPackageMinimumKeyboardVersion(pkgInfo); + if (FileUtils.compareVersions(pkgMinimumKeyboardVersion, KMManager.getMajorVersion()) == FileUtils.VERSION_GREATER) { + showErrorToast(context, getString(R.string.minimum_keyboard_version_not_supported)); + return; + } + pkgName = kmpProcessor.getPackageName(pkgInfo); final int keyboardCount = kmpProcessor.getKeyboardCount(pkgInfo); diff --git a/android/KMAPro/kMAPro/src/main/res/values/strings.xml b/android/KMAPro/kMAPro/src/main/res/values/strings.xml index 8dda950bd0..736669d822 100644 --- a/android/KMAPro/kMAPro/src/main/res/values/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values/strings.xml @@ -241,4 +241,7 @@ Invalid/Missing metadata in package + + + Keyboard package has functionality not supported with this version of Keyman diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java index b4b935fac2..9a06a1255f 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java @@ -394,6 +394,22 @@ public class PackageProcessor { } } + /** + * Parse a kmp.json JSON object and return the package's minimum keyboard version (system.fileVersion). + * This is to avoid issues with app crashing if keyboard functionality is not supported. + * If undefined, return default version "7.0". + * @param json kmp.json as a JSON object. + * @return String of the package's minimum keyboard version + */ + public static String getPackageMinimumKeyboardVersion(JSONObject json) { + try { + return json.getJSONObject("system").getString("fileVersion"); + } catch (Exception e) { + KMLog.LogException(TAG, "", e); + return "7.0"; + } + } + /** * Parse a kmp.json JSON object and return the package's target (keyboards vs lexical models). * Only one can be valid. Otherwise, return "invalid" diff --git a/common/test/keyboards/the_99/README.md b/common/test/keyboards/the_99/README.md new file mode 100644 index 0000000000..4479efe738 --- /dev/null +++ b/common/test/keyboards/the_99/README.md @@ -0,0 +1,34 @@ +the 99 keyboard +============== + +Version 1.0 + +Description +----------- +the 99 generated from template. kmp.json manually edited to have system.fileVersion = "99.0" +to validate the minimum keyboard version is checked before package installation. + +Links +----- +See Github issue #6254 +https://github.com/keymanapp/keyman/issues/6254 + + +Copyright +--------- +See [LICENSE.md](LICENSE.md) + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/common/test/keyboards/the_99/the_99.kmp b/common/test/keyboards/the_99/the_99.kmp new file mode 100644 index 0000000000000000000000000000000000000000..f63460167040bc5145b7a9293eae3a93f350dabc GIT binary patch literal 3770 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 pP^Upl%Rh?1--Ulq;6q^ Date: Thu, 10 Mar 2022 14:03:29 +0700 Subject: [PATCH 17/46] chore(common): Update caps_3620_3621 to fileVersion 15.0 --- .../full_caps_3620_3621/source/full_caps_3620_3621.kmn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn index aa7c9aa40a..ad51b8f95b 100644 --- a/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn +++ b/common/test/keyboards/full_caps_3620_3621/source/full_caps_3620_3621.kmn @@ -1,6 +1,6 @@ c full_caps_3620_3621 generated from template at 2021-12-01 08:45:15 c with name "full_caps_3620_3621" -store(&VERSION) '10.0' +store(&VERSION) '15.0' store(&NAME) 'full_caps_3620_3621' store(©RIGHT) '©' store(&KEYBOARDVERSION) '1.0' From 6a622b4255501f227ded999c48740a33031160e3 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 10 Mar 2022 15:24:21 +0700 Subject: [PATCH 18/46] fix(android/engine): Activate menu on globe longpress before release --- .../main/java/com/tavultesoft/kmea/KMKeyboard.java | 6 +++++- .../main/java/com/tavultesoft/kmea/KMManager.java | 13 +++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index d40da0d67c..3d253b944b 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -189,7 +189,11 @@ final class KMKeyboard extends WebView { showSubKeys(context); return; } else if (KMManager.getGlobeKeyState() == KMManager.GlobeKeyState.GLOBE_KEY_STATE_DOWN) { - KMManager.setGlobeKeyState(KMManager.GlobeKeyState.GLOBE_KEY_STATE_LONGPRESS); + // Shortcut to keyboard picker menu (Ignore if system keyboard on lock screen) + // Do we need to make KMManager.doGlobeKeyLongpressAction() public? + if ((keyboardType != KeyboardType.KEYBOARD_TYPE_SYSTEM) || !KMManager.isLocked()) { + KMManager.showKeyboardPicker(context, keyboardType); + } return; /* For future implementation else if(suggestionJSON != null) { diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 963c74d9a7..e858a5d882 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -2099,6 +2099,16 @@ public final class KMManager { globeKeyState = state; } + /** + * Return if the lock screen is locked (prevents keyboard picker menu from being displayed) + * @return boolean + */ + public static boolean isLocked() { + KeyguardManager keyguardManager = (KeyguardManager) appContext.getSystemService(Context.KEYGUARD_SERVICE); + // inKeyguardRestrictedInputMode() deprecated, so check isKeyguardLocked() to determine if screen is locked + return keyguardManager.isKeyguardLocked(); + } + /** * Handle the globe key action * @param globeKeyDown boolean if the globe key state is GLOBE_KEY_STATE_DOWN @@ -2111,9 +2121,8 @@ public final class KMManager { } if (KMManager.shouldAllowSetKeyboard()) { - KeyguardManager keyguardManager = (KeyguardManager) appContext.getSystemService(Context.KEYGUARD_SERVICE); // inKeyguardRestrictedInputMode() deprecated, so check isKeyguardLocked() to determine if screen is locked - if (keyguardManager.isKeyguardLocked()) { + if (isLocked()) { if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM && globeKeyState == GlobeKeyState.GLOBE_KEY_STATE_UP) { doGlobeKeyLockscreenAction(context); } From c3c8c219d7d0fbe10c571d6b6360809e0d573a66 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 10 Mar 2022 19:41:03 +0700 Subject: [PATCH 19/46] chore(android/engine): Tweak handling globe key --- .../app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java | 7 ++----- .../app/src/main/java/com/tavultesoft/kmea/KMManager.java | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index 3d253b944b..f5cf3f5137 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -189,11 +189,8 @@ final class KMKeyboard extends WebView { showSubKeys(context); return; } else if (KMManager.getGlobeKeyState() == KMManager.GlobeKeyState.GLOBE_KEY_STATE_DOWN) { - // Shortcut to keyboard picker menu (Ignore if system keyboard on lock screen) - // Do we need to make KMManager.doGlobeKeyLongpressAction() public? - if ((keyboardType != KeyboardType.KEYBOARD_TYPE_SYSTEM) || !KMManager.isLocked()) { - KMManager.showKeyboardPicker(context, keyboardType); - } + KMManager.setGlobeKeyState(KMManager.GlobeKeyState.GLOBE_KEY_STATE_LONGPRESS); + KMManager.handleGlobeKeyAction(context, true, keyboardType); return; /* For future implementation else if(suggestionJSON != null) { diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index e858a5d882..bc57a1971b 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -2103,7 +2103,7 @@ public final class KMManager { * Return if the lock screen is locked (prevents keyboard picker menu from being displayed) * @return boolean */ - public static boolean isLocked() { + private static boolean isLocked() { KeyguardManager keyguardManager = (KeyguardManager) appContext.getSystemService(Context.KEYGUARD_SERVICE); // inKeyguardRestrictedInputMode() deprecated, so check isKeyguardLocked() to determine if screen is locked return keyguardManager.isKeyguardLocked(); @@ -2114,7 +2114,7 @@ public final class KMManager { * @param globeKeyDown boolean if the globe key state is GLOBE_KEY_STATE_DOWN * @param keyboardType KeyboardType KEYBOARD_TYPE_INAPP or KEYBOARD_TYPE_SYSTEM */ - private static void handleGlobeKeyAction(Context context, boolean globeKeyDown, KeyboardType keyboardType) { + public static void handleGlobeKeyAction(Context context, boolean globeKeyDown, KeyboardType keyboardType) { // Update globeKeyState if (globeKeyState != GlobeKeyState.GLOBE_KEY_STATE_LONGPRESS) { globeKeyState = globeKeyDown ? GlobeKeyState.GLOBE_KEY_STATE_DOWN : GlobeKeyState.GLOBE_KEY_STATE_UP; From 0023841ee457a4a4df4c8ad8454b5e59c46555f1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 11 Mar 2022 04:40:53 +1100 Subject: [PATCH 20/46] chore(web): address review comments --- .../web/keyboard-processor/src/text/keyboardProcessor.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts index 59e15c6c5f..75439369bc 100644 --- a/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts +++ b/common/core/web/keyboard-processor/src/text/keyboardProcessor.ts @@ -718,13 +718,13 @@ namespace com.keyman.text { // I3318 (always clear deadkeys after backspace) outputTarget.deadkeys().clear(); } else if(KeyboardProcessor.isModifier(Levent)) { - // For eventual integration - we bypass an OSK update for physical keystrokes when in touch mode. this.activeKeyboard.notify(Levent.Lcode, outputTarget, isKeyDown ? 1 : 0); - if(!Levent.device.touchable) { + // For eventual integration - we bypass an OSK update for physical keystrokes when in touch mode. + if(!Levent.device.touchable) { return this._UpdateVKShift(Levent); // I2187 - } else { + } else { return true; - } + } } if(Levent.LmodifierChange) { From c177f142d3892f0073bf17664f96c1353b81710b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 11 Mar 2022 05:23:37 +1100 Subject: [PATCH 21/46] fix(common): allow custom keyboard builds This allows for custom builds of keyboards, e.g. where a keyboard is manually constructed for testing purposes. --- common/test/keyboards/build.sh | 35 ++++++++++----- common/test/keyboards/the_99/build.sh | 63 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 10 deletions(-) mode change 100644 => 100755 common/test/keyboards/build.sh create mode 100755 common/test/keyboards/the_99/build.sh diff --git a/common/test/keyboards/build.sh b/common/test/keyboards/build.sh old mode 100644 new mode 100755 index 176b79cd50..d3f6c0700a --- a/common/test/keyboards/build.sh +++ b/common/test/keyboards/build.sh @@ -124,18 +124,24 @@ if ! $QUIET; then fi clean() { - local kpj="$1.kpj" ss= + local kpj="$1.kpj" ss= s= if $QUIET; then ss=-ss + s=-s fi pushd "$1" > /dev/null - $KMCOMP_LAUNCHER "$KMCOMP" -c $ss "$kpj" + if [ -f build.sh ]; then + ./build.sh -c $s + else + $KMCOMP_LAUNCHER "$KMCOMP" -c $ss "$kpj" + fi popd > /dev/null } build() { - local kpj="$1.kpj" d= t= ss= target= + local kpj="$1.kpj" d= t= ss= target= s= k= if $KEYBOARDS_ONLY; then + k=-k t=-t target="$1.kmn" fi @@ -143,12 +149,17 @@ build() { d=-d fi if $QUIET; then + s=-s ss=-ss fi # -w - treat warnings as errors, we'll force this # -cfc - check filename conventions pushd "$1" > /dev/null - $KMCOMP_LAUNCHER "$KMCOMP" $d $ss -w -cfc "$kpj" $t "$target" + if [ -f build.sh ]; then + ./build.sh $d $k $s + else + $KMCOMP_LAUNCHER "$KMCOMP" $d $ss -w -cfc "$kpj" $t "$target" + fi popd > /dev/null } @@ -156,14 +167,18 @@ build() { for TARGET in "${TARGETS[@]}"; do if $CLEAN; then - echo - echo_heading "Cleaning target $TARGET" - echo + if ! $QUIET; then + echo + echo_heading "Cleaning target $TARGET" + echo + fi clean "$TARGET" else - echo - echo_heading "Building target $TARGET" - echo + if ! $QUIET; then + echo + echo_heading "Building target $TARGET" + echo + fi build "$TARGET" fi done diff --git a/common/test/keyboards/the_99/build.sh b/common/test/keyboards/the_99/build.sh new file mode 100755 index 0000000000..8ea4680ada --- /dev/null +++ b/common/test/keyboards/the_99/build.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set -e +set -u + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../../../resources/build/build-utils.sh" +# . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +## END STANDARD BUILD SCRIPT INCLUDE +THIS_DIR="$(dirname "$THIS_SCRIPT")" + +display_usage() { + echo "Usage: build.sh [-c]" + exit $1 +} + +# Parse args +shopt -s nocasematch + +CLEAN=false +DEBUG=false +QUIET=false +KEYBOARDS_ONLY=false + +while [[ $# -gt 0 ]] ; do + key="$1" + case $key in + --help|-h|-\?) + display_usage 0 + ;; + --clean|-c) + CLEAN=true + ;; + --debug|-d) + DEBUG=true + ;; + --silent|-s) + QUIET=true + ;; + --keyboard|-k) + KEYBOARDS_ONLY=true + ;; + *) + display_usage 1 + ;; + esac + shift +done + +if $CLEAN; then + if ! $QUIET; then + echo Cleaning the_99.kmp from build/ + fi + rm -rf "$THIS_DIR"/build +else + if ! $QUIET; then + echo Copying the_99.kmp to build/ + fi + mkdir -p "$THIS_DIR"/build + cp "$THIS_DIR"/the_99.kmp build/the_99.kmp +fi \ No newline at end of file From faff0e2aefb1c6238e0b884306dd8e1deee2c0f5 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 11 Mar 2022 05:42:08 +1100 Subject: [PATCH 22/46] fix(common): address review comment Don't specify wine as kmcomp launcher if a custom kmcomp is provided on the command line. --- common/test/keyboards/build.sh | 56 ++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/common/test/keyboards/build.sh b/common/test/keyboards/build.sh index d3f6c0700a..dd7ace24a0 100755 --- a/common/test/keyboards/build.sh +++ b/common/test/keyboards/build.sh @@ -37,6 +37,7 @@ QUIET=false DEBUG=false CLEAN=false KEYBOARDS_ONLY=false +CUSTOM_KMCOMP= KMCOMP="$KEYMAN_ROOT/windows/bin/developer/kmcomp.exe" TARGETS=() @@ -64,6 +65,7 @@ while [[ $# -gt 0 ]] ; do --kmcomp) shift KMCOMP="$1" + CUSTOM_KMCOMP=true ;; *) TARGETS+=("$key") @@ -75,35 +77,35 @@ done # don't currently have a binary version of kmcomp available # during Linux and macOS builds, so that will need to be # manually sourced. +KMCOMP_LAUNCHER= -case "${OSTYPE}" in - "cygwin") - KMCOMP_LAUNCHER= - ;; - "msys") - KMCOMP_LAUNCHER= - ;; - "darwin"*) - # For Catalina (10.15) onwards, must use wine64 - base_macos_ver=10.15 - macos_ver=$(sw_vers -productVersion) - if verlt "$macos_ver" "$base_macos_ver"; then +if ! $CUSTOM_KMCOMP; then + case "${OSTYPE}" in + "cygwin") + ;; + "msys") + ;; + "darwin"*) + # For Catalina (10.15) onwards, must use wine64 + base_macos_ver=10.15 + macos_ver=$(sw_vers -productVersion) + if verlt "$macos_ver" "$base_macos_ver"; then + KMCOMP_LAUNCHER=wine + else + # On Catalina, and later versions: + # wine-4.12.1 works; wine-5.0, wine-5.7 do not. + # retrieve these from: + # `brew tap gcenx/wine && brew install --cask --no-quarantine wine-crossover` + # may also need to `sudo spctl --master-disable` + KMCOMP_LAUNCHER=wine64 + KMCOMP="$(dirname $KMCOMP)/kmcomp.x64.exe" + fi + ;; + *) KMCOMP_LAUNCHER=wine - else - # On Catalina, and later versions: - # wine-4.12.1 works; wine-5.0, wine-5.7 do not. - # retrieve these from: - # `brew tap gcenx/wine && brew install --cask --no-quarantine wine-crossover` - # may also need to `sudo spctl --master-disable` - KMCOMP_LAUNCHER=wine64 - KMCOMP="$(dirname $KMCOMP)/kmcomp.x64.exe" - fi - ;; - *) - KMCOMP_LAUNCHER=wine - ;; -esac - + ;; + esac +fi # Build list of available targets from subfolders, if none specified if [ ${#TARGETS[@]} == 0 ]; then From a64ead928709570eb8154197905c5893987b9af6 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 10 Mar 2022 13:49:17 -0500 Subject: [PATCH 23/46] auto: increment beta version to 15.0.212 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- developer/server/package-lock.json | 2 +- developer/server/package.json | 2 +- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 31 files changed, 76 insertions(+), 71 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 0a5860a7e1..92ba30272e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 15.0.211 beta 2022-03-10 + +* fix(oem/fv/android): Check keyboard exists before registering a model (#6346) +* chore(common): cleanup sh global color variables (#6353) + ## 15.0.210 beta 2022-03-10 * feat(common): build test keyboards via script (#6352) diff --git a/VERSION.md b/VERSION.md index d7162a38bf..00a78d4d99 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.211 \ No newline at end of file +15.0.212 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 0823023b26..8fc327215b 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index f8bfed33d2..5f7f754e6e 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.211", + "version": "15.0.212", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.211", - "@keymanapp/resources-gosh": "^15.0.211", + "@keymanapp/lexical-model-compiler": "^15.0.212", + "@keymanapp/resources-gosh": "^15.0.212", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.211", - "@keymanapp/lexical-model-layer": "^15.0.211", - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/keyboard-processor": "^15.0.212", + "@keymanapp/lexical-model-layer": "^15.0.212", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index fd7533149c..f44cfc65d4 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index d5b462478e..186889b3f1 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.211", + "version": "15.0.212", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.211", + "@keymanapp/resources-gosh": "^15.0.212", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index c6aa597b93..38ff441363 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index c29bc0cad9..ddf7c2be18 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.211", + "version": "15.0.212", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.211", - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/keyboard-processor": "^15.0.212", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index e72110017c..be46a67ced 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index 680a0b372f..c5ff388480 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.211", + "version": "15.0.212", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.211", + "@keymanapp/web-environment": "^15.0.212", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index d99d453960..a0b4b96fe3 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index f9d801aea5..4dac112926 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.211", + "version": "15.0.212", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", + "@keymanapp/resources-gosh": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 61fbd18da0..bf9f5a61bd 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 8e5896f921..bc6800a739 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.211", + "version": "15.0.212", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.211" + "@keymanapp/models-wordbreakers": "^15.0.212" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index aa2235ae9e..b80a8bf599 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 502b8c151e..13bc4b6f51 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.211", + "version": "15.0.212", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index 009f524959..229bccb2f2 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index ce17181344..a90a4ee531 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.211", + "version": "15.0.212", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.211", + "@keymanapp/models-types": "^15.0.212", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 4708764a1b..cf48246d69 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 441f84922a..9cd197b0fd 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.211", + "version": "15.0.212", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/resources-gosh": "^15.0.211", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/resources-gosh": "^15.0.212", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.211", - "@keymanapp/models-wordbreakers": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/models-templates": "^15.0.212", + "@keymanapp/models-wordbreakers": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index e9f86e6d49..95d1b3a0e4 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index d6110c62dd..d0edcd6c75 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.211", + "version": "15.0.212", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.211", + "@keymanapp/models-types": "^15.0.212", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.211", - "@keymanapp/models-wordbreakers": "^15.0.211", + "@keymanapp/models-templates": "^15.0.212", + "@keymanapp/models-wordbreakers": "^15.0.212", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/developer/server/package-lock.json b/developer/server/package-lock.json index 85e02f8f68..6fcada346c 100644 --- a/developer/server/package-lock.json +++ b/developer/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/server/package.json b/developer/server/package.json index 09eca855d5..0fd1c46ee7 100644 --- a/developer/server/package.json +++ b/developer/server/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.211", + "version": "15.0.212", "description": "Keyman Developer backend server", "main": "dist/index.js", "scripts": { diff --git a/lerna.json b/lerna.json index 06bd20d972..d3b6718cbd 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "ts-node", "typescript" ], - "version": "15.0.211" + "version": "15.0.212" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index e74d68f5d9..cec9b79141 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index addfce08b2..bc16986e7d 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.211", + "version": "15.0.212", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index e506a8102a..a677fa56c8 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 2cb3fbc417..301e47f11a 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.211", + "version": "15.0.212", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.211" + "@keymanapp/resources-gosh": "^15.0.212" } } diff --git a/web/package-lock.json b/web/package-lock.json index 446fd75e19..3f9fdf873a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.211", + "version": "15.0.212", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index fbf5fa52a0..d1a0a42646 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.211", + "version": "15.0.212", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.211", - "@keymanapp/web-sentry-manager": "^15.0.211", + "@keymanapp/resources-gosh": "^15.0.212", + "@keymanapp/web-sentry-manager": "^15.0.212", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.211", - "@keymanapp/keyboard-processor": "^15.0.211", - "@keymanapp/lexical-model-layer": "^15.0.211", - "@keymanapp/models-types": "^15.0.211", - "@keymanapp/recorder-core": "^15.0.211", - "@keymanapp/web-environment": "^15.0.211", - "@keymanapp/web-utils": "^15.0.211", + "@keymanapp/input-processor": "^15.0.212", + "@keymanapp/keyboard-processor": "^15.0.212", + "@keymanapp/lexical-model-layer": "^15.0.212", + "@keymanapp/models-types": "^15.0.212", + "@keymanapp/recorder-core": "^15.0.212", + "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-utils": "^15.0.212", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From 4cad24cac3d80ef3e34a514a7861f1383552967e Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 10 Mar 2022 20:30:44 +0100 Subject: [PATCH 24/46] chore(linux): Fix lintian warnings --- .editorconfig | 3 ++- CONTRIBUTING.md | 3 ++- linux/debian/control | 4 +++- linux/debian/ibus-keyman.manpages | 2 +- linux/debian/keyman.install | 2 +- linux/debian/rules | 2 ++ linux/{debian => ibus-keyman}/man/ibus-engine-keyman.1 | 0 linux/{debian => keyman-config}/km-config.desktop | 0 8 files changed, 11 insertions(+), 5 deletions(-) rename linux/{debian => ibus-keyman}/man/ibus-engine-keyman.1 (100%) rename linux/{debian => keyman-config}/km-config.desktop (100%) diff --git a/.editorconfig b/.editorconfig index a17a535817..f68c86a948 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,8 @@ insert_final_newline = true trim_trailing_whitespace = true [*.md] -max_line_length = off +# Lintian in Debian complains about lines > 512 +max_line_length = 512 [{Makefile,rules}] indent_style = tab diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7354c987f5..15924ad455 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,7 +115,8 @@ Include details about your configuration and environment: This section guides you through submitting an enhancement suggestion for Keyman, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:. -Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](https://github.com/keymanapp/keyman/issues/new?assignees=&labels=feat&template=feature_request.md&title=feat%3A+), including the steps that you imagine you would take if the feature you're requesting existed. +Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). +Fill in [the template](https://github.com/keymanapp/keyman/issues/new?assignees=&labels=feat&template=feature_request.md&title=feat%3A+), including the steps that you imagine you would take if the feature you're requesting existed. #### Before Submitting An Enhancement Suggestion diff --git a/linux/debian/control b/linux/debian/control index 3346bd0238..10d6272b9f 100644 --- a/linux/debian/control +++ b/linux/debian/control @@ -40,13 +40,15 @@ Standards-Version: 4.5.1 Vcs-Git: https://github.com/keymanapp/keyman.git Vcs-Browser: https://github.com/keymanapp/keyman Homepage: https://www.keyman.com +Rules-Requires-Root: binary-targets Package: keyman Architecture: all Depends: libglib2.0-bin, python3-keyman-config (= ${binary:Version}), - ibus-keyman (= ${binary:Version}), + ibus-keyman (>= ${binary:Version}), + ibus-keyman (<< ${binary:Version}.1~), ${misc:Depends}, Recommends: onboard-keyman, diff --git a/linux/debian/ibus-keyman.manpages b/linux/debian/ibus-keyman.manpages index a85b71d286..82aa3721aa 100644 --- a/linux/debian/ibus-keyman.manpages +++ b/linux/debian/ibus-keyman.manpages @@ -1 +1 @@ -debian/man/ibus-engine-keyman.1 +linux/ibus-keyman/man/ibus-engine-keyman.1 diff --git a/linux/debian/keyman.install b/linux/debian/keyman.install index 4bc765e59b..8096e324ae 100644 --- a/linux/debian/keyman.install +++ b/linux/debian/keyman.install @@ -10,5 +10,5 @@ linux/keyman-config/icons/48/km-config.png usr/share/icons/hicolor/48x48/apps/ linux/keyman-config/icons/64/application-x-kmp.png usr/share/icons/hicolor/64x64/mimetypes/ linux/keyman-config/icons/64/km-config.png usr/share/icons/hicolor/64x64/apps/ linux/keyman-config/keyman_config/icons/* usr/share/keyman/icons/ +linux/keyman-config/km-config.desktop usr/share/applications debian/com.keyman.config.appdata.xml usr/share/metainfo -debian/km-config.desktop usr/share/applications diff --git a/linux/debian/rules b/linux/debian/rules index 5effa0a117..d7995a7881 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -44,12 +44,14 @@ override_dh_auto_build: dh_auto_build --sourcedir=linux/keyman-config --buildsystem=pybuild $@ override_dh_auto_test: + ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) # keymankeyboardprocessor cd common/core/desktop && ./build.sh tests # ibus-keyman cd linux/ibus-keyman && make check VERBOSE=1 # keyman-config dh_auto_test --sourcedir=linux/keyman-config --buildsystem=pybuild $@ + endif override_dh_auto_install: # keymankeyboardprocessor diff --git a/linux/debian/man/ibus-engine-keyman.1 b/linux/ibus-keyman/man/ibus-engine-keyman.1 similarity index 100% rename from linux/debian/man/ibus-engine-keyman.1 rename to linux/ibus-keyman/man/ibus-engine-keyman.1 diff --git a/linux/debian/km-config.desktop b/linux/keyman-config/km-config.desktop similarity index 100% rename from linux/debian/km-config.desktop rename to linux/keyman-config/km-config.desktop From 1e2939f82e6cb94000cb49750b899c246b95ef84 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Fri, 11 Mar 2022 06:21:07 +0700 Subject: [PATCH 25/46] Update android/KMAPro/kMAPro/src/main/res/values/strings.xml Co-authored-by: Marc Durdin --- android/KMAPro/kMAPro/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/KMAPro/kMAPro/src/main/res/values/strings.xml b/android/KMAPro/kMAPro/src/main/res/values/strings.xml index 736669d822..e248b971ab 100644 --- a/android/KMAPro/kMAPro/src/main/res/values/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values/strings.xml @@ -243,5 +243,5 @@ - Keyboard package has functionality not supported with this version of Keyman + Keyboard requires a newer version of Keyman From 2133e7f6ead66b57011d9cdc4ded9ff7f795de84 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 11 Mar 2022 09:10:10 +0100 Subject: [PATCH 26/46] chore(linux): Fix previous commit --- linux/debian/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/debian/rules b/linux/debian/rules index d7995a7881..f32d01f500 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -44,14 +44,14 @@ override_dh_auto_build: dh_auto_build --sourcedir=linux/keyman-config --buildsystem=pybuild $@ override_dh_auto_test: - ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) # keymankeyboardprocessor cd common/core/desktop && ./build.sh tests # ibus-keyman cd linux/ibus-keyman && make check VERBOSE=1 # keyman-config dh_auto_test --sourcedir=linux/keyman-config --buildsystem=pybuild $@ - endif +endif override_dh_auto_install: # keymankeyboardprocessor From 412a9ea2fcccc00f86e187bc9462cab1268a573b Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 11 Mar 2022 09:24:38 +0100 Subject: [PATCH 27/46] chore(linux): Fix another lintian warning --- linux/keyman-config/buildtools/build-langtags.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/keyman-config/buildtools/build-langtags.py b/linux/keyman-config/buildtools/build-langtags.py index 6253087df0..d05e9746a6 100755 --- a/linux/keyman-config/buildtools/build-langtags.py +++ b/linux/keyman-config/buildtools/build-langtags.py @@ -42,7 +42,7 @@ class LangTagsMap(): if len(lang['tag']) < 3: map3To2.append("'%s': '%s'" % (lang['iso639_3'], lang['tag'])) langTags.append( - "'%s': { 'full': '%s', 'region': '%s', 'script': '%s', 'suppress': %s }" % (lang['tag'], lang['full'], region, script, suppress)) + "'%s': {'full': '%s', 'region': '%s', 'script': '%s', 'suppress': %s}" % (lang['tag'], lang['full'], region, script, suppress)) allTags.append("'%s': '%s'" % (lang['tag'], lang['tag'])) if lang['tag'] != lang['full']: allTags.append("'%s': '%s'" % (lang['full'], lang['tag'])) @@ -52,8 +52,8 @@ class LangTagsMap(): allTags.append("'%s': '%s'" % (tag, lang['tag'])) langTagsString = ',\n '.join(map(str, langTags)) - allTagsString = ', '.join(allTags) - map3To2String = ', '.join(map3To2) + allTagsString = ',\n '.join(allTags) + map3To2String = ',\n '.join(map3To2) outputFile.write(" __langTags = {\n %s }\n\n" % langTagsString) outputFile.write(" __allTags = { %s }\n\n" % allTagsString) outputFile.write(" __map3To2 = { %s }\n" % map3To2String) From cc0317af2c5b37d8397b924c00c60fad6bfbcfbb Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 11 Mar 2022 18:14:02 +0100 Subject: [PATCH 28/46] fix(linux): Don't use restart option of exit() Instead of trying to restart ibus by passing True to bus.exit() we now exit ibus and then let verify_ibus_daemon() start it again. Also added additional checks to verify that we're not running multiple ibus-daemons at the start of km-config and before restarting. --- .../keyman-config/keyman_config/ibus_util.py | 19 +++++++++++++------ linux/keyman-config/km-config | 3 +++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/linux/keyman-config/keyman_config/ibus_util.py b/linux/keyman-config/keyman_config/ibus_util.py index bded6aa119..e335f80a32 100644 --- a/linux/keyman-config/keyman_config/ibus_util.py +++ b/linux/keyman-config/keyman_config/ibus_util.py @@ -79,7 +79,7 @@ def restart_ibus_subp(): subprocess.run(["ibus", "restart"]) -def _verify_ibus_daemon(): +def verify_ibus_daemon(start): logging.info('**** Verify ibus running') realuser = os.environ.get('SUDO_USER') user = os.environ.get('USER') @@ -90,10 +90,12 @@ def _verify_ibus_daemon(): try: ps = subprocess.run(('ps', '--user', user, '-o', 's=', '-o', 'cmd'), stdout=subprocess.PIPE).stdout - logging.info('**** running processes: %s', ps.decode('utf-8')) + debugps = subprocess.run(('bash', '-c', 'ps -ef | grep ibus-daemon'), stdout=subprocess.PIPE).stdout + logging.info('**** running processes: %s', debugps.decode('utf-8')) ibus_daemons = re.findall('^[^ZT] ibus-daemon .*--xim.*', ps.decode('utf-8'), re.MULTILINE) if len(ibus_daemons) <= 0: - _start_ibus_daemon(realuser) + if start: + _start_ibus_daemon(realuser) elif len(ibus_daemons) > 1: logging.error('More than one ibus-daemon instance running! Keyman keyboards might not work as expected. ' 'Please reboot your machine.') @@ -102,7 +104,8 @@ def _verify_ibus_daemon(): except subprocess.CalledProcessError as e: # Log critical error in order to track down #6237 logging.critical('getting ibus-daemon failed (%s: %s)', type(e), e.args) - _start_ibus_daemon(realuser) + if start: + _start_ibus_daemon(realuser) def _start_ibus_daemon(realuser): @@ -124,6 +127,7 @@ def _start_ibus_daemon(realuser): def restart_ibus(bus=None): + verify_ibus_daemon(False) realuser = os.environ.get('SUDO_USER') if realuser: # we have been called with `sudo`. Restart ibus for the real user. @@ -136,14 +140,17 @@ def restart_ibus(bus=None): bus = get_ibus_bus() if bus: logging.info("restarting IBus") - bus.exit(True) + # we no longer try to restart since we sometimes ended up with more than one + # ibus-daemon process (#6237). Instead we only exit ibus here, and start + # ibus again below. + bus.exit(False) bus.destroy() except Exception as e: logging.warning("Failed to restart IBus") logging.warning(e) # give ibus a chance to shutdown (#6237) time.sleep(1) # 1s - _verify_ibus_daemon() + verify_ibus_daemon(True) def bus_has_engine(bus, name): diff --git a/linux/keyman-config/km-config b/linux/keyman-config/km-config index e954c4813e..30f8a21ece 100755 --- a/linux/keyman-config/km-config +++ b/linux/keyman-config/km-config @@ -5,6 +5,7 @@ import logging from keyman_config import __versionwithtag__, __pkgversion__ from keyman_config.handle_install import download_and_install_package +from keyman_config.ibus_util import verify_ibus_daemon if __name__ == '__main__': @@ -40,6 +41,8 @@ if __name__ == '__main__': logging.info('Keyman version %s %s', __versionwithtag__, __pkgversion__) + verify_ibus_daemon(False) + if args.install: download_and_install_package(args.install) elif args.url: From 7fe1997754154e4f69e0f9c9b8f87d053840408f Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 11 Mar 2022 13:02:26 -0500 Subject: [PATCH 29/46] auto: increment beta version to 15.0.213 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- developer/server/package-lock.json | 2 +- developer/server/package.json | 2 +- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 31 files changed, 76 insertions(+), 71 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 92ba30272e..417daa0d3f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 15.0.212 beta 2022-03-11 + +* chore(linux): Fix lintian warnings (#6360) +* fix(common): allow custom keyboard builds (#6358) + ## 15.0.211 beta 2022-03-10 * fix(oem/fv/android): Check keyboard exists before registering a model (#6346) diff --git a/VERSION.md b/VERSION.md index 00a78d4d99..2f56ef3079 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.212 \ No newline at end of file +15.0.213 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 8fc327215b..6e5e60d4be 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 5f7f754e6e..cb2be22a31 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.212", + "version": "15.0.213", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.212", - "@keymanapp/resources-gosh": "^15.0.212", + "@keymanapp/lexical-model-compiler": "^15.0.213", + "@keymanapp/resources-gosh": "^15.0.213", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.212", - "@keymanapp/lexical-model-layer": "^15.0.212", - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/keyboard-processor": "^15.0.213", + "@keymanapp/lexical-model-layer": "^15.0.213", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index f44cfc65d4..c9dc4a3ce2 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 186889b3f1..90f123201a 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.212", + "version": "15.0.213", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.212", + "@keymanapp/resources-gosh": "^15.0.213", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index 38ff441363..ccf01236fc 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index ddf7c2be18..b97900f6a3 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.212", + "version": "15.0.213", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.212", - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/keyboard-processor": "^15.0.213", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index be46a67ced..9c008a4c53 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index c5ff388480..50c5bcd3c1 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.212", + "version": "15.0.213", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/web-environment": "^15.0.213", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index a0b4b96fe3..c7274e8009 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index 4dac112926..556a8b20f4 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.212", + "version": "15.0.213", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", + "@keymanapp/resources-gosh": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index bf9f5a61bd..d568a67559 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index bc6800a739..145e210afa 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.212", + "version": "15.0.213", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.212" + "@keymanapp/models-wordbreakers": "^15.0.213" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index b80a8bf599..b98c5749cf 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 13bc4b6f51..50eb31ee8f 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.212", + "version": "15.0.213", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index 229bccb2f2..cf8043a3c2 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index a90a4ee531..390e5d912e 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.212", + "version": "15.0.213", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.212", + "@keymanapp/models-types": "^15.0.213", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index cf48246d69..8dc2a719bf 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 9cd197b0fd..c9a8b36799 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.212", + "version": "15.0.213", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/resources-gosh": "^15.0.212", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/resources-gosh": "^15.0.213", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.212", - "@keymanapp/models-wordbreakers": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/models-templates": "^15.0.213", + "@keymanapp/models-wordbreakers": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index 95d1b3a0e4..1b0dc2ed16 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index d0edcd6c75..aa013907b7 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.212", + "version": "15.0.213", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.212", + "@keymanapp/models-types": "^15.0.213", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.212", - "@keymanapp/models-wordbreakers": "^15.0.212", + "@keymanapp/models-templates": "^15.0.213", + "@keymanapp/models-wordbreakers": "^15.0.213", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/developer/server/package-lock.json b/developer/server/package-lock.json index 6fcada346c..0e1cb3a2b3 100644 --- a/developer/server/package-lock.json +++ b/developer/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/server/package.json b/developer/server/package.json index 0fd1c46ee7..9e44f11840 100644 --- a/developer/server/package.json +++ b/developer/server/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.212", + "version": "15.0.213", "description": "Keyman Developer backend server", "main": "dist/index.js", "scripts": { diff --git a/lerna.json b/lerna.json index d3b6718cbd..ba04cf6243 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "ts-node", "typescript" ], - "version": "15.0.212" + "version": "15.0.213" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index cec9b79141..64ea9292c0 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index bc16986e7d..e4c9d0d75b 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.212", + "version": "15.0.213", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index a677fa56c8..cc5107ea79 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 301e47f11a..04124b39ea 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.212", + "version": "15.0.213", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.212" + "@keymanapp/resources-gosh": "^15.0.213" } } diff --git a/web/package-lock.json b/web/package-lock.json index 3f9fdf873a..0ed0ee5075 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.212", + "version": "15.0.213", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index d1a0a42646..b62b228b4a 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.212", + "version": "15.0.213", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.212", - "@keymanapp/web-sentry-manager": "^15.0.212", + "@keymanapp/resources-gosh": "^15.0.213", + "@keymanapp/web-sentry-manager": "^15.0.213", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.212", - "@keymanapp/keyboard-processor": "^15.0.212", - "@keymanapp/lexical-model-layer": "^15.0.212", - "@keymanapp/models-types": "^15.0.212", - "@keymanapp/recorder-core": "^15.0.212", - "@keymanapp/web-environment": "^15.0.212", - "@keymanapp/web-utils": "^15.0.212", + "@keymanapp/input-processor": "^15.0.213", + "@keymanapp/keyboard-processor": "^15.0.213", + "@keymanapp/lexical-model-layer": "^15.0.213", + "@keymanapp/models-types": "^15.0.213", + "@keymanapp/recorder-core": "^15.0.213", + "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-utils": "^15.0.213", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From 2fc52af7191683a8335d8429882e915143b90dca Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 14 Mar 2022 07:03:16 +1100 Subject: [PATCH 30/46] feat(common): zip and index keyboard artifacts --- common/test/keyboards/.gitignore | 4 ++- common/test/keyboards/build.sh | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/common/test/keyboards/.gitignore b/common/test/keyboards/.gitignore index ef4be49c85..eab8a63166 100644 --- a/common/test/keyboards/.gitignore +++ b/common/test/keyboards/.gitignore @@ -1 +1,3 @@ -*/build/ \ No newline at end of file +*/build/ +*/*_source.zip +index.html diff --git a/common/test/keyboards/build.sh b/common/test/keyboards/build.sh index dd7ace24a0..f3a3c69f06 100755 --- a/common/test/keyboards/build.sh +++ b/common/test/keyboards/build.sh @@ -21,6 +21,9 @@ display_usage() { echo " --keyboard, -k Build only keyboards (not packages)" echo " --kmcomp path Specify path to kmcomp.exe, defaults" echo " to windows/bin/developer/kmcomp.exe" + echo " --zip-source Create zip file for source of each" + echo " keyboard for artifact tests" + echo " --index Build index.html for artifact tests" echo echo "Targets (all unless specified):" @@ -38,6 +41,8 @@ DEBUG=false CLEAN=false KEYBOARDS_ONLY=false CUSTOM_KMCOMP= +INDEX=false +ZIPSOURCE=false KMCOMP="$KEYMAN_ROOT/windows/bin/developer/kmcomp.exe" TARGETS=() @@ -62,6 +67,12 @@ while [[ $# -gt 0 ]] ; do --keyboard|-k) KEYBOARDS_ONLY=true ;; + --zip-source) + ZIPSOURCE=true + ;; + --index) + INDEX=true + ;; --kmcomp) shift KMCOMP="$1" @@ -122,6 +133,8 @@ if ! $QUIET; then "QUIET: $QUIET" \ "KEYBOARDS_ONLY: $KEYBOARDS_ONLY" \ "TARGETS: ${TARGETS[@]}" \ + "ZIPSOURCE: $ZIPSOURCE" \ + "INDEX: $INDEX" \ "" fi @@ -165,6 +178,13 @@ build() { popd > /dev/null } +zipsource() { + local target="$1" + pushd "$1" > /dev/null + 7z a -r -x!build -x"!$target.kpj.user" "${target}_source.zip" . + popd > /dev/null +} + ### for TARGET in "${TARGETS[@]}"; do @@ -182,7 +202,44 @@ for TARGET in "${TARGETS[@]}"; do echo fi build "$TARGET" + + if $ZIPSOURCE; then + zipsource "$TARGET" + fi fi done +### + +if $INDEX; then + if $CLEAN; then + rm -f "$THIS_DIR/index.html" + else + cat << EOF > "$THIS_DIR/index.html" + + + + + Test Keyboards - $VERSION_WITH_TAG + + +

Test Keyboards - $VERSION_WITH_TAG

+
    +EOF + + for TARGET in "${TARGETS[@]}"; do + if $ZIPSOURCE; then + echo "
  • $TARGET.kmp (source)
  • " >> "$THIS_DIR/index.html" + else + echo "
  • $TARGET.kmp
  • " >> "$THIS_DIR/index.html" + fi + done + + cat << 'EOF' >> "$THIS_DIR/index.html" +
+ + +EOF + fi +fi exit 0 From 738b3cc08af8696533678b7d8c61596813129d20 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 9 Mar 2022 09:38:31 +0700 Subject: [PATCH 31/46] fix(oem/fv/android): Fold model picker into Keyboard settings menu --- .../java/com/tavultesoft/kmea/KMManager.java | 12 +- .../tavultesoft/kmea/ModelPickerActivity.java | 2 +- .../KMEA/app/src/main/res/values/strings.xml | 10 +- .../keyboards/FVKeyboardListAdapter.java | 4 - .../keyboards/FVKeyboardSettingsActivity.java | 255 +++++++++++++----- .../keyboards/FVRegionListAdapter.java | 4 - .../firstvoices/keyboards/MainActivity.java | 34 +-- .../fv_keyboard_settings_list_layout.xml | 50 ++-- .../main/res/layout/fv_list_row_layout.xml | 3 +- .../main/res/layout/keyboard_row_layout.xml | 5 +- .../src/main/res/layout/region_row_layout.xml | 4 +- .../app/src/main/res/values/strings.xml | 1 + 12 files changed, 238 insertions(+), 146 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 963c74d9a7..c87330f544 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1325,7 +1325,17 @@ public final class KMManager { return true; } - public static boolean setBannerOptions(boolean mayPredict) { + /** + * deleteLexicalModel - Remove lexical model from the installed list + * and deregister the model with KMW + * @param context + * @param position - int position in the models list + */ + public static void deleteLexicalModel(Context context, int position, boolean silenceNotification) { + KeyboardPickerActivity.deleteLexicalModel(context, position, silenceNotification); + } + + public static boolean setBannerOptions(boolean mayPredict) { String url = KMString.format("setBannerOptions(%s)", mayPredict); if (InAppKeyboard != null) { InAppKeyboard.loadJavascript(url); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java index 819c2b71a0..b43e403190 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java @@ -275,7 +275,7 @@ public final class ModelPickerActivity extends BaseActivity { // Uses the repo dataset's master lexical model list to create a filtered adapter for use here. // As this one is specific to this class, we can implement Activity-specific functionality within it. - static private class FilteredLexicalModelAdapter extends NestedAdapter { + static public class FilteredLexicalModelAdapter extends NestedAdapter { static final int RESOURCE = R.layout.models_list_row_layout; private final Context context; diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml index 2b59b03306..27ef7195f0 100644 --- a/android/KMEA/app/src/main/res/values/strings.xml +++ b/android/KMEA/app/src/main/res/values/strings.xml @@ -97,7 +97,6 @@ Updates available for dictionary %1$s: %2$s - Keyboard version @@ -133,6 +132,9 @@ Checking for associated dictionary to download + + Cannot connect to Keyman server to check for associated dictionary to download + Would you like to download the latest version of this dictionary? @@ -210,10 +212,14 @@ Dictionary + + Dictionary + Dictionaries + Check for available dictionary - + Check for dictionaries online Dictionary: %1$s diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardListAdapter.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardListAdapter.java index 8f43bd8d90..6deba05efd 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardListAdapter.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardListAdapter.java @@ -54,10 +54,6 @@ class FVKeyboardListAdapter extends ArrayAdapter { holder.nextButton = convertView.findViewById(R.id.imageNext); holder.nextButton.setOnClickListener(new FVKeyboardListAdapter.FVOnClickNextListener()); convertView.setTag(holder); - - if (listFont != null) { - holder.text1.setTypeface(listFont, Typeface.BOLD); - } } else { holder = (ViewHolder) convertView.getTag(); } diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java index 6b844f0fd5..aa16529f67 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java @@ -1,12 +1,18 @@ package com.firstvoices.keyboards; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.database.DataSetObserver; import android.os.Bundle; import android.view.View; import android.view.Window; -import android.widget.ImageView; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -15,7 +21,10 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.Toolbar; +import com.tavultesoft.kmea.KMKeyboardDownloaderActivity; import com.tavultesoft.kmea.KMManager; +import com.tavultesoft.kmea.KeyboardPickerActivity; +import com.tavultesoft.kmea.ModelInfoActivity; import com.tavultesoft.kmea.ModelPickerActivity; import com.tavultesoft.kmea.cloud.CloudApiTypes; import com.tavultesoft.kmea.cloud.CloudDownloadMgr; @@ -24,9 +33,12 @@ import com.tavultesoft.kmea.data.CloudRepository; import com.tavultesoft.kmea.data.Dataset; import com.tavultesoft.kmea.data.Keyboard; import com.tavultesoft.kmea.data.KeyboardController; +import com.tavultesoft.kmea.data.LexicalModel; import com.tavultesoft.kmea.util.BCP47; import com.tavultesoft.kmea.util.KMLog; +import com.tavultesoft.kmea.util.MapCompat; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; @@ -38,12 +50,14 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { private static Toolbar toolbar = null; private static TextView fvKeyboardTextView = null; private static TextView fvVersionTextView = null; - private static TextView lexicalModelTextView = null; private static TextView correctionsTextView = null; private static SwitchCompat fvKeyboardToggle = null; private static SwitchCompat correctionsToggle = null; + private static ModelPickerActivity.FilteredLexicalModelAdapter listAdapter = null; private String associatedLexicalModel = ""; private String lgCode; + private static RelativeLayout checkModelLayout = null; + private static ListView listView = null; private String lgName; private String kbId; private String kbName; @@ -51,6 +65,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { private String version; private SharedPreferences prefs; + private DataSetObserver repoObserver; private static Dataset repo; private boolean didExecuteParser = false; @@ -117,11 +132,17 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { } } - // Force the cloud catalog to update + // Establish the list view based on the CloudRepository's Dataset if (!didExecuteParser) { didExecuteParser = true; repo = CloudRepository.shared.fetchDataset(context); } + // add listener to dataset to get event for catalog update. + repoObserver = new DataSetObserver() { + @Override public void onChanged() { + } + }; + repo.registerDataSetObserver(repoObserver); kbId = bundle.getString(KMManager.KMKey_KeyboardID); kbName = bundle.getString(KMManager.KMKey_KeyboardName); @@ -131,6 +152,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); + int actionBarHeight = toolbar.getLayoutParams().height; getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(false); @@ -149,22 +171,8 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { public void onClick(View v) { // If keyboard enabled, determine if associated lexical model should be downloaded // Check if associated model is not already installed - if (fvKeyboardToggle.isChecked() && (KMManager.getAssociatedLexicalModel(lgCode) == null) && KMManager.hasConnection(context)) { - String _downloadid = CloudLexicalModelMetaDataDownloadCallback.createDownloadId(lgCode); - CloudLexicalModelMetaDataDownloadCallback _callback = new CloudLexicalModelMetaDataDownloadCallback(); - - Toast.makeText(context, - context.getString(R.string.query_associated_model), - Toast.LENGTH_SHORT).show(); - - ArrayList aPreparedCloudApiParams = new ArrayList<>(); - String url = CloudRepository.prepareLexicalModelQuery(lgCode); - aPreparedCloudApiParams.add(new CloudApiTypes.CloudApiParam( - CloudApiTypes.ApiTarget.KeyboardLexicalModels, url).setType(CloudApiTypes.JSONType.Array)); - - CloudDownloadMgr.getInstance().executeAsDownload( - context, _downloadid, null, _callback, - aPreparedCloudApiParams.toArray(new CloudApiTypes.CloudApiParam[0])); + if (fvKeyboardToggle.isChecked() && (KMManager.getAssociatedLexicalModel(lgCode) == null)) { + queryModel(); } FVShared.getInstance().setCheckState(kbId, fvKeyboardToggle.isChecked()); @@ -197,72 +205,179 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { overrideCorrectionsToggle(mayPredict); - layout = (RelativeLayout)findViewById(R.id.model_picker); - textView = (TextView) layout.findViewById(R.id.text1); - textView.setText(getString(R.string.model_label)); + checkModelLayout = (RelativeLayout)findViewById(R.id.check_model); + textView = checkModelLayout.findViewById(R.id.text1); + textView.setText(getString(R.string.check_model_online)); - lexicalModelTextView = layout.findViewById(R.id.text2); - - updateActiveLexicalModel(); - - ImageView imageView = (ImageView) layout.findViewById(R.id.image1); - imageView.setImageResource(R.drawable.ic_arrow_forward); - layout.setEnabled(true); - layout.setOnClickListener(new View.OnClickListener() { + checkModelLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // Start ModelPickerActivity - Bundle bundle = new Bundle(); - bundle.putString(KMManager.KMKey_LanguageID, lgCode); - bundle.putString(KMManager.KMKey_LanguageName, lgName); - bundle.putString(KMManager.KMKey_CustomHelpLink, customHelpLink); - Intent i = new Intent(context, ModelPickerActivity.class); - i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - i.putExtras(bundle); - startActivity(i); + queryModel(); } }); - /** - * This is a placeholder for "Manage dictionary" settings - * - * layout = (RelativeLayout)findViewById(R.id.manage_dictionary); - * textView = (TextView) layout.findViewById(R.id.text1); - * textView.setText(getString(R.string.manage_dictionary)); - * imageView = (ImageView) layout.findViewById(R.id.image1); - * imageView.setImageResource(R.drawable.ic_arrow_forward); - */ + // Display model picker list + listView = (ListView)findViewById(R.id.listView); + listView.setFastScrollEnabled(true); + + // Initialize the dataset of available lexical models (installed and from the cloud catalog) + listAdapter = new ModelPickerActivity.FilteredLexicalModelAdapter(context, repo, lgCode); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, View view, final int position, long id) { + int selectedIndex = position; + LexicalModel model = ((ModelPickerActivity.FilteredLexicalModelAdapter) listView.getAdapter()).getItem(position); + String packageID = model.getPackageID(); + String languageID = model.getLanguageID(); + String modelID = model.getLexicalModelID(); + String modelName = model.getLexicalModelName(); + String langName = model.getLanguageName(); + String version = model.getVersion(); + + boolean immediateRegister = false; + + // File check to see if lexical model file already exists locally (may not be currently installed) + File modelCheck = new File(KMManager.getLexicalModelsDir() + packageID + File.separator + modelID + ".model.js"); + String modelKey = model.getKey(); + boolean modelInstalled = KeyboardPickerActivity.containsLexicalModel(context, modelKey); + if (modelInstalled) { + // Show Model Info + listView.setItemChecked(position, true); + listView.setSelection(position); + + // Start intent for selected Predictive Text Model screen + Intent i = new Intent(context, ModelInfoActivity.class); + i.putExtra(KMManager.KMKey_LexicalModel, model); + startActivityForResult(i, 1); + } else if (modelCheck.exists()) { + // Handle scenario where previously installed kmp already exists so + // we only need to add the model to the list of installed models + HashMap modelInfo = new HashMap(); + modelInfo.put(KMManager.KMKey_PackageID, packageID); + modelInfo.put(KMManager.KMKey_LexicalModelID, modelID); + modelInfo.put(KMManager.KMKey_LanguageID, languageID); + modelInfo.put(KMManager.KMKey_LexicalModelName, modelName); + modelInfo.put(KMManager.KMKey_LanguageName, langName); + modelInfo.put(KMManager.KMKey_LexicalModelVersion, version); + // Add help link + modelInfo.put(KMManager.KMKey_CustomHelpLink, ""); + + boolean result = KMManager.addLexicalModel(context, new HashMap<>(modelInfo)); + if (result) { + Toast.makeText(context, getString(R.string.model_install_toast), Toast.LENGTH_SHORT).show(); + } + + immediateRegister = true; + } else { + // Model isn't installed so prompt to download it + Bundle args = model.buildDownloadBundle(); + Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class); + i.putExtras(args); + startActivity(i); + } + + // If we had a previously-installed lexical model, we should 'deinstall' it so that only + // one model is actively linked to any given language. + if(!modelInstalled && !immediateRegister) { + // While awkward, we must obtain the preInstalledModelMap before any installations occur. + // We don't want to remove the model we just installed, after all! + HashMap preInstalledModelMap = KMManager.getAssociatedLexicalModel(languageID); + if(preInstalledModelMap != null) { + // This might be unnecessary + LexicalModel preInstalled = new LexicalModel( + preInstalledModelMap.get(KMManager.KMKey_PackageID), + preInstalledModelMap.get(KMManager.KMKey_LexicalModelID), + preInstalledModelMap.get(KMManager.KMKey_LexicalModelName), + preInstalledModelMap.get(KMManager.KMKey_LanguageID), + preInstalledModelMap.get(KMManager.KMKey_LanguageName), + preInstalledModelMap.get(KMManager.KMKey_LexicalModelVersion), + preInstalledModelMap.get(KMManager.KMKey_CustomHelpLink), + MapCompat.getOrDefault(preInstalledModelMap, KMManager.KMKey_KMPLink, "")); + String itemKey = preInstalled.getKey(); + int modelIndex = KeyboardPickerActivity.getLexicalModelIndex(context, itemKey); + KMManager.deleteLexicalModel(context, modelIndex, true); + } + } + + if(immediateRegister) { + // Register associated lexical model if it matches the active keyboard's language code; + // it's safe since we're on the same thread. Needs to be called AFTER deinstalling the old one. + String kbdLgCode = KMManager.getCurrentKeyboardInfo(context).getLanguageID(); + if(BCP47.languageEquals(kbdLgCode, languageID)) { + KMManager.registerAssociatedLexicalModel(languageID); + } + } + + // Force a display refresh. + notifyDataSetChanged(); + } + }); + + Intent i = getIntent(); + listView.setSelectionFromTop(i.getIntExtra("listPosition", 0), + i.getIntExtra("offsetY", 0)); + + // Rescale listview and hide "Dictionaries" header if no dictionaries installed + updateDictionariesSection(); + } + + public void updateDictionariesSection() { + if (listAdapter != null && toolbar != null) { + int actionBarHeight = toolbar.getLayoutParams().height; + int numModels = listAdapter.getCount(); + listView.getLayoutParams().height = actionBarHeight * (numModels); + + TextView label = findViewById(R.id.model_label); + if (label != null) { + if (numModels == 0) { + label.setVisibility(View.GONE); + } else { + label.setVisibility(VISIBLE); + } + } + } + } + + private void queryModel() { + if (!KMManager.hasConnection(context)) { + Toast.makeText(context, + context.getString(R.string.cannot_query_associated_model), + Toast.LENGTH_SHORT).show(); + return; + } + + String _downloadid = CloudLexicalModelMetaDataDownloadCallback.createDownloadId(lgCode); + CloudLexicalModelMetaDataDownloadCallback _callback = new CloudLexicalModelMetaDataDownloadCallback(); + + Toast.makeText(context, + context.getString(R.string.query_associated_model), + Toast.LENGTH_SHORT).show(); + + ArrayList aPreparedCloudApiParams = new ArrayList<>(); + String url = CloudRepository.prepareLexicalModelQuery(lgCode); + aPreparedCloudApiParams.add(new CloudApiTypes.CloudApiParam( + CloudApiTypes.ApiTarget.KeyboardLexicalModels, url).setType(CloudApiTypes.JSONType.Array)); + + CloudDownloadMgr.getInstance().executeAsDownload( + context, _downloadid, null, _callback, + aPreparedCloudApiParams.toArray(new CloudApiTypes.CloudApiParam[0])); } @Override public void onResume() { super.onResume(); - updateActiveLexicalModel(); + notifyDataSetChanged(); } - /** - * Updates the active lexical model label with the name of the associated lexical model. - * If there's no associated lexical model, the label displays a prompt to check for an available model. - */ - public void updateActiveLexicalModel() { - HashMap lexModelMap = KMManager.getAssociatedLexicalModel(lgCode); - if(lexModelMap != null) { - associatedLexicalModel = lexModelMap.get(KMManager.KMKey_LexicalModelName); - } else { - // Prompt to check for available dictionary - associatedLexicalModel = getString(R.string.check_available_model); + public static void notifyDataSetChanged() { + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); } - lexicalModelTextView.setText(associatedLexicalModel); - lexicalModelTextView.setEnabled(true); - } - - public static void setActiveLexicalModelLabel(String lexicalModelLabel) { - if (lexicalModelTextView != null && lexicalModelLabel != null && !lexicalModelLabel.isEmpty()) { - lexicalModelTextView.setText(lexicalModelLabel); - lexicalModelTextView.setEnabled(true); - } + //updateDictionariesSection(); } @Override @@ -295,7 +410,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { } if (correctionsToggle != null) { correctionsToggle.setEnabled(override); - int visibility = override ? View.VISIBLE : View.INVISIBLE; + int visibility = override ? VISIBLE : INVISIBLE; correctionsToggle.setVisibility(visibility); } } diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVRegionListAdapter.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVRegionListAdapter.java index e61e9ce29a..3792fc9453 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVRegionListAdapter.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVRegionListAdapter.java @@ -37,10 +37,6 @@ final class FVRegionListAdapter extends ArrayAdapter { holder.text1 = convertView.findViewById(R.id.text1); holder.text2 = convertView.findViewById(R.id.text2); - if (listFont != null) { - holder.text1.setTypeface(listFont, Typeface.BOLD); - holder.text2.setTypeface(listFont, Typeface.NORMAL); - } convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java index 747a938cfa..c232bf19be 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java @@ -89,10 +89,6 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa webView.getSettings().setUseWideViewPort(true); webView.getSettings().setLoadWithOverviewMode(true); webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - /* - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.setWebContentsDebuggingEnabled(true); - }*/ webView.setWebViewClient(new WebViewClient() { @Override @@ -204,30 +200,6 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa // ensure onKeyboardDownloadFinished() gets called } - /* - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } - */ - private static final class JSHandler { final private Context context; @@ -281,13 +253,11 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa KMManager.getCurrentKeyboardInfo(this).getLanguageID() : KMManager.KMDefault_LanguageID; boolean matchingModel = false; - String lexicalModelName = ""; for(int i=0; ilexicalModelInfo = new HashMap<>(lexicalModelsInstalled.get(i)); if(lexicalModelInfo.get(KMManager.KMKey_LanguageID).equals(langId)) { matchingModel = true; - lexicalModelName = lexicalModelInfo.get(KMManager.KMKey_LexicalModelName); } KMManager.addLexicalModel(this, lexicalModelInfo); } @@ -298,8 +268,8 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa KMManager.registerAssociatedLexicalModel(langId); // Update associated dictionary string if applicable - FVKeyboardSettingsActivity.setActiveLexicalModelLabel(lexicalModelName); - + FVKeyboardSettingsActivity.notifyDataSetChanged(); + //FVKeyboardSettingsActivity.updateDictionariesSection(context); } } diff --git a/oem/firstvoices/android/app/src/main/res/layout/fv_keyboard_settings_list_layout.xml b/oem/firstvoices/android/app/src/main/res/layout/fv_keyboard_settings_list_layout.xml index 0f192968b2..bdc2f0cf73 100644 --- a/oem/firstvoices/android/app/src/main/res/layout/fv_keyboard_settings_list_layout.xml +++ b/oem/firstvoices/android/app/src/main/res/layout/fv_keyboard_settings_list_layout.xml @@ -1,12 +1,10 @@ - + - - + + + + + + + + + - - - - - - - - - diff --git a/oem/firstvoices/android/app/src/main/res/layout/fv_list_row_layout.xml b/oem/firstvoices/android/app/src/main/res/layout/fv_list_row_layout.xml index dfa0725335..dc04f86bb7 100644 --- a/oem/firstvoices/android/app/src/main/res/layout/fv_list_row_layout.xml +++ b/oem/firstvoices/android/app/src/main/res/layout/fv_list_row_layout.xml @@ -22,8 +22,7 @@ android:layout_marginTop="5dp" android:ellipsize="end" android:singleLine="true" - android:textSize="16sp" - android:textStyle="bold" /> + android:textSize="16sp" /> - + android:textSize="14sp" /> + + android:textSize="16sp" /> diff --git a/oem/firstvoices/android/app/src/main/res/values/strings.xml b/oem/firstvoices/android/app/src/main/res/values/strings.xml index 02f85987a0..83edf8f86b 100644 --- a/oem/firstvoices/android/app/src/main/res/values/strings.xml +++ b/oem/firstvoices/android/app/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ Setup Regions Keyboards + Dictionaries %1$s Settings Enable keyboard Version %1$s From e138ca382ef62722efcda46f789dd6732338c900 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 9 Mar 2022 12:02:56 +0700 Subject: [PATCH 32/46] fix(oem/fv/android): Toggle predictions when dictionary installed --- .../keyboards/FVKeyboardSettingsActivity.java | 4 ++-- .../java/com/firstvoices/keyboards/MainActivity.java | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java index aa16529f67..592ce72c29 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java @@ -182,8 +182,8 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { // The following two layouts/toggles will need to link with these objects. Context appContext = this.getApplicationContext(); prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); - boolean mayPredict = prefs.getBoolean(KMManager.getLanguagePredictionPreferenceKey(lgCode), true); - boolean mayCorrect = prefs.getBoolean(KMManager.getLanguageCorrectionPreferenceKey(lgCode), true); + boolean mayPredict = prefs.getBoolean(KMManager.getLanguagePredictionPreferenceKey(lgCode), false); + boolean mayCorrect = prefs.getBoolean(KMManager.getLanguageCorrectionPreferenceKey(lgCode), false); layout = (RelativeLayout)findViewById(R.id.corrections_toggle); diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java index c232bf19be..f0f1afcf8e 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java @@ -2,6 +2,7 @@ package com.firstvoices.keyboards; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -254,13 +255,21 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa KMManager.KMDefault_LanguageID; boolean matchingModel = false; + SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + for(int i=0; ilexicalModelInfo = new HashMap<>(lexicalModelsInstalled.get(i)); if(lexicalModelInfo.get(KMManager.KMKey_LanguageID).equals(langId)) { matchingModel = true; } KMManager.addLexicalModel(this, lexicalModelInfo); + + // Enable predictions and corrections toggles + editor.putBoolean(KMManager.getLanguagePredictionPreferenceKey(lexicalModelInfo.get(KMManager.KMKey_LanguageID)), true); + editor.putBoolean(KMManager.getLanguageCorrectionPreferenceKey(lexicalModelInfo.get(KMManager.KMKey_LanguageID)), true); } + editor.commit(); // We're on the main thread, so if the active keyboard's language code matches, // let's register the associated lexical model. From 2b7d10718be07b6eeba8dd19abda8a856cfac9cf Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 9 Mar 2022 14:52:11 +0700 Subject: [PATCH 33/46] fix(oem/fv/android): Refresh Settings menu --- .../keyboards/FVKeyboardSettingsActivity.java | 16 +++++++++++----- .../com/firstvoices/keyboards/MainActivity.java | 8 +++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java index 592ce72c29..bf2ca8bc4b 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java @@ -3,6 +3,7 @@ package com.firstvoices.keyboards; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -11,7 +12,6 @@ import android.os.Bundle; import android.view.View; import android.view.Window; import android.widget.AdapterView; -import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -46,7 +46,7 @@ import java.util.HashMap; * Displays an FV Keyboard enable and some lexical model switches. */ public final class FVKeyboardSettingsActivity extends AppCompatActivity { - private Context context; + private static Context context = null; private static Toolbar toolbar = null; private static TextView fvKeyboardTextView = null; private static TextView fvVersionTextView = null; @@ -57,6 +57,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { private String associatedLexicalModel = ""; private String lgCode; private static RelativeLayout checkModelLayout = null; + private static Bundle bundle = null; private static ListView listView = null; private String lgName; private String kbId; @@ -119,7 +120,9 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { context = this; setContentView(R.layout.fv_keyboard_settings_list_layout); - Bundle bundle = getIntent().getExtras(); + if (getIntent() != null && getIntent().getExtras() != null) { + bundle = getIntent().getExtras(); + } if (bundle == null) { // Should never actually happen. KMLog.LogError(TAG, "Language data not specified for FVKeyboardSettingsActivity!"); @@ -152,7 +155,6 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); - int actionBarHeight = toolbar.getLayoutParams().height; getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(false); @@ -376,8 +378,12 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } + } - //updateDictionariesSection(); + public static void restartActivity() { + if (context != null) { + ((Activity)context).recreate(); + } } @Override diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java index f0f1afcf8e..b0e71e885e 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java @@ -28,7 +28,7 @@ import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity implements OnKeyboardDownloadEventListener { - public static Context context; + public Context context; FVDownloadResultReceiver resultReceiver; @@ -275,12 +275,10 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa // let's register the associated lexical model. if(matchingModel) { KMManager.registerAssociatedLexicalModel(langId); - - // Update associated dictionary string if applicable - FVKeyboardSettingsActivity.notifyDataSetChanged(); - //FVKeyboardSettingsActivity.updateDictionariesSection(context); } + // Launch/refresh FV Keyboard Settings menu + FVKeyboardSettingsActivity.restartActivity(); } } From 8aadea6086cb15025639b868414fffd8adbfecad Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Mon, 14 Mar 2022 08:43:10 +0700 Subject: [PATCH 34/46] fix(oem/fv/android): Refresh menu on install --- .../keyboards/FVKeyboardSettingsActivity.java | 11 +++++++---- .../java/com/firstvoices/keyboards/MainActivity.java | 12 +++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java index bf2ca8bc4b..02e00f7c40 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVKeyboardSettingsActivity.java @@ -57,6 +57,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { private String associatedLexicalModel = ""; private String lgCode; private static RelativeLayout checkModelLayout = null; + private static Intent intent = null; private static Bundle bundle = null; private static ListView listView = null; private String lgName; @@ -121,7 +122,8 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { setContentView(R.layout.fv_keyboard_settings_list_layout); if (getIntent() != null && getIntent().getExtras() != null) { - bundle = getIntent().getExtras(); + intent = getIntent(); + bundle = intent.getExtras(); } if (bundle == null) { // Should never actually happen. @@ -182,8 +184,7 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { }); // The following two layouts/toggles will need to link with these objects. - Context appContext = this.getApplicationContext(); - prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); + prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); boolean mayPredict = prefs.getBoolean(KMManager.getLanguagePredictionPreferenceKey(lgCode), false); boolean mayCorrect = prefs.getBoolean(KMManager.getLanguageCorrectionPreferenceKey(lgCode), false); @@ -382,7 +383,9 @@ public final class FVKeyboardSettingsActivity extends AppCompatActivity { public static void restartActivity() { if (context != null) { - ((Activity)context).recreate(); + // Not using Activity.recreate() because we need to recalculate the items + ((Activity)context).finish(); + ((Activity)context).startActivity(intent); } } diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java index b0e71e885e..5d3e5c5939 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java @@ -19,6 +19,7 @@ import io.sentry.android.core.SentryAndroid; import com.tavultesoft.kmea.*; import com.tavultesoft.kmea.data.Keyboard; +import com.tavultesoft.kmea.util.BCP47; import com.tavultesoft.kmea.util.DownloadFileUtils; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener; @@ -250,7 +251,7 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa @Override public void onLexicalModelInstalled(List> lexicalModelsInstalled) { - String langId = (KMManager.getCurrentKeyboardInfo(this) != null) ? + String keyboardLangId = (KMManager.getCurrentKeyboardInfo(this) != null) ? KMManager.getCurrentKeyboardInfo(this).getLanguageID() : KMManager.KMDefault_LanguageID; boolean matchingModel = false; @@ -260,21 +261,22 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa for(int i=0; ilexicalModelInfo = new HashMap<>(lexicalModelsInstalled.get(i)); - if(lexicalModelInfo.get(KMManager.KMKey_LanguageID).equals(langId)) { + String lexicalModelLangId = lexicalModelInfo.get(KMManager.KMKey_LanguageID); + if(BCP47.languageEquals(keyboardLangId, lexicalModelLangId)) { matchingModel = true; } KMManager.addLexicalModel(this, lexicalModelInfo); // Enable predictions and corrections toggles - editor.putBoolean(KMManager.getLanguagePredictionPreferenceKey(lexicalModelInfo.get(KMManager.KMKey_LanguageID)), true); - editor.putBoolean(KMManager.getLanguageCorrectionPreferenceKey(lexicalModelInfo.get(KMManager.KMKey_LanguageID)), true); + editor.putBoolean(KMManager.getLanguagePredictionPreferenceKey(lexicalModelLangId), true); + editor.putBoolean(KMManager.getLanguageCorrectionPreferenceKey(lexicalModelLangId), true); } editor.commit(); // We're on the main thread, so if the active keyboard's language code matches, // let's register the associated lexical model. if(matchingModel) { - KMManager.registerAssociatedLexicalModel(langId); + KMManager.registerAssociatedLexicalModel(keyboardLangId); } // Launch/refresh FV Keyboard Settings menu From a3202e0ff9a85fe30ca221cecbca3df495bcdce3 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Mon, 14 Mar 2022 13:00:44 +0700 Subject: [PATCH 35/46] handle delete with null context before --- .../Classes/Keyboard/InputViewController.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Keyboard/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Keyboard/InputViewController.swift index 031bb9daab..ec7807110f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Keyboard/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Keyboard/InputViewController.swift @@ -287,7 +287,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { return } - // What the actual heck, Apple. Apparently, in system-keyboard mode, this is also self-triggered if we erase back to a newline. + // Apparently, in system-keyboard mode, this is also self-triggered if we erase back to a newline. // Refer to https://github.com/keymanapp/keyman/pull/2770 for context. if self.swallowBackspaceTextChange && Manager.shared.isSystemKeyboard && textDocumentProxy.documentContextBeforeInput == "\n" { self.swallowBackspaceTextChange = false @@ -333,6 +333,11 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { return } + if numCharsToDelete > 0 && textDocumentProxy.documentContextBeforeInput == nil { + textDocumentProxy.deleteBackward() + return + } + for _ in 0.. Date: Mon, 14 Mar 2022 10:27:55 +0100 Subject: [PATCH 36/46] chore(linux): Update changelogs for 14.0.287 --- linux/debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux/debian/changelog b/linux/debian/changelog index aeb9a9b16e..c36501f290 100644 --- a/linux/debian/changelog +++ b/linux/debian/changelog @@ -1,9 +1,17 @@ keyman (15.0.90-1) UNRELEASED; urgency=medium * Consolidate source packages + Closes: #1007123 -- Eberhard Beilharz Mon, 02 Aug 2021 18:13:58 +0200 +keyman-config (14.0.287-1) unstable; urgency=medium + + * New upstream release + * Re-release to Debian + + -- Eberhard Beilharz Fri, 11 Mar 2022 12:32:34 +0100 + keyman-config (14.0.284-3) unstable; urgency=medium * Team upload From cab9ced56dddfad355bc04deab7077a9ca0f6967 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 14 Mar 2022 10:32:29 +0100 Subject: [PATCH 37/46] chore(linux): Update copyright --- linux/debian/copyright | 137 ++++++++++++++++++++++-- linux/ibus-keyman/tests/ibusimcontext.c | 1 + linux/ibus-keyman/tests/ibusimcontext.h | 1 + 3 files changed, 131 insertions(+), 8 deletions(-) diff --git a/linux/debian/copyright b/linux/debian/copyright index 837c30622f..e7bb6aadc1 100644 --- a/linux/debian/copyright +++ b/linux/debian/copyright @@ -1,28 +1,101 @@ -Format: http://anonscm.debian.org/viewvc/dep/web/deps/dep5.mdwn?view=markup&pathrev=174 +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: keyman Upstream-Contact: Keyman team +Source: https://github.com/keymanapp/keyman Files: * -Copyright: Copyright (C) 2018-2021 SIL International -License: MIT +Copyright: 2018-2022 SIL International +License: Expat Files: linux/ibus-keyman/* -Copyright: 2004-2021 SIL International +Copyright: 2004-2022 SIL International License: GPL-2+ Files: linux/ibus-keyman/src/keymanutil.c linux/ibus-keyman/src/keymanutil.h linux/ibus-keyman/src/kmpdetails.c linux/ibus-keyman/src/kmpdetails.h -Copyright: 2009-2021 SIL International -License: GPL-2+ or MIT +Copyright: 2009-2022 SIL International +License: GPL-2+ or Expat Files: linux/ibus-keyman/src/keyman-service.c linux/ibus-keyman/src/keyman-service.h -Copyright: 2018-2021 SIL International + linux/keyman-config/buildtools/help2md +Copyright: 2018-2022 SIL International License: GPL-3+ -License: MIT +Files: linux/ibus-keyman/config.rpath + linux/ibus-keyman/m4/* +Copyright: 1996-2003, 2009-2015, Free Software Foundation, Inc. +License: FSFULLR + +Files: linux/ibus-keyman/Makefile.am + linux/ibus-keyman/Makefile.in + linux/ibus-keyman/compile + linux/ibus-keyman/configure.ac + linux/ibus-keyman/depcomp + linux/ibus-keyman/m4/Makefile.am + linux/ibus-keyman/m4/Makefile.in + linux/ibus-keyman/missing + linux/ibus-keyman/src/Makefile.am + linux/ibus-keyman/src/Makefile.in + linux/ibus-keyman/src/engine.c + linux/ibus-keyman/src/engine.h + linux/ibus-keyman/src/main.c + linux/ibus-keyman/src/test/Makefile.am + linux/ibus-keyman/src/test/Makefile.in + linux/ibus-keyman/tap-driver.sh + linux/ibus-keyman/test-driver + linux/ibus-keyman/tests/Makefile.am + linux/ibus-keyman/tests/Makefile.in +Copyright: 1994-2017, Free Software Foundation, Inc. + 2009-2022, SIL International +License: GPL-2+ + +Files: linux/ibus-keyman/m4/gettext.m4 + linux/ibus-keyman/m4/intl.m4 + linux/ibus-keyman/m4/intldir.m4 + linux/ibus-keyman/m4/intlmacosx.m4 + linux/ibus-keyman/m4/lcmessage.m4 + linux/ibus-keyman/m4/nls.m4 + linux/ibus-keyman/m4/po.m4 + linux/ibus-keyman/m4/progtest.m4 +Copyright: 1995--2014, Free Software Foundation, Inc. +License: FSFULLR and/or GPL-3 and/or LGPL-3 + +Files: linux/ibus-keyman/install-sh + linux/keyman-config/COPYING +Copyright: 1994, X Consortium + 2018, SIL International +License: Expat + +Files: linux/ibus-keyman/INSTALL + linux/ibus-keyman/po/Makefile.in.in +Copyright: 1994-1996, 1999-2002, 2004-2016, Free Software Foundation, Inc. + 1995-1997, 2000-2007, 2009-2010, Ulrich Drepper +License: FSFAP + +Files: linux/ibus-keyman/icons/Makefile.am + linux/ibus-keyman/icons/Makefile.in +Copyright: 1994-2017, Free Software Foundation, Inc. + 2018, SIL International +License: LGPL-2+ + +Files: linux/ibus-keyman/tests/ibusimcontext.c + linux/ibus-keyman/tests/ibusimcontext.h +Copyright: 2008-2010, Peng Huang + 2008-2010, Red Hat, Inc. + 2008-2013, Peng Huang + 2008-2021, Red Hat, Inc. + 2015-2021, Takao Fujiwara + 2021-2022, SIL International +License: LGPL-2.1+ + +Files: linux/keyman-config/buildtools/help2man +Copyright: 1997-2005, 2009-2017, 2020-2021, Free Software Foundation, Inc. +License: GPL-3+ + +License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including @@ -79,3 +152,51 @@ License: GPL-3+ On Debian systems, the full text of the GNU General Public License version 3 can be found in the file `/usr/share/common-licenses/GPL-3'. + +License: FSFULLR + This file is free software; the Free Software Foundation gives unlimited + permission to copy and/or distribute it, with or without modifications, as long + as this notice is preserved. + +License: FSFAP + Copying and distribution of this file, with or without modification, are + permitted in any medium without royalty provided the copyright notice and this + notice are preserved. This file is offered as-is, without any warranty. + +License: LGPL-2+ + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Library General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + . + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more + details. + . + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the full text of the GNU Library General Public + License version 2 can be found in the file + `/usr/share/common-licenses/LGPL-2'. + +License: LGPL-2.1+ + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + . + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + . + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the full text of the GNU Lesser General Public + License version 2.1 can be found in the file + `/usr/share/common-licenses/LGPL-2.1'. diff --git a/linux/ibus-keyman/tests/ibusimcontext.c b/linux/ibus-keyman/tests/ibusimcontext.c index 248c2833cf..ba958daaec 100644 --- a/linux/ibus-keyman/tests/ibusimcontext.c +++ b/linux/ibus-keyman/tests/ibusimcontext.c @@ -4,6 +4,7 @@ * Copyright (C) 2008-2013 Peng Huang * Copyright (C) 2015-2021 Takao Fujiwara * Copyright (C) 2008-2021 Red Hat, Inc. + * Copyright (C) 2021-2022 SIL International * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/linux/ibus-keyman/tests/ibusimcontext.h b/linux/ibus-keyman/tests/ibusimcontext.h index 3d901dbc0a..f45b404a26 100644 --- a/linux/ibus-keyman/tests/ibusimcontext.h +++ b/linux/ibus-keyman/tests/ibusimcontext.h @@ -3,6 +3,7 @@ /* ibus - The Input Bus * Copyright (C) 2008-2010 Peng Huang * Copyright (C) 2008-2010 Red Hat, Inc. + * Copyright (C) 2021-2022 SIL International * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public From 4d0dfbe3a58949371edd884da9f82565b162f87e Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 14 Mar 2022 10:32:46 +0100 Subject: [PATCH 38/46] chore(linux): Update Standards-Version --- linux/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/debian/control b/linux/debian/control index 10d6272b9f..a599ab7ae6 100644 --- a/linux/debian/control +++ b/linux/debian/control @@ -36,7 +36,7 @@ Build-Depends: xvfb, metacity, gawk, -Standards-Version: 4.5.1 +Standards-Version: 4.6.0 Vcs-Git: https://github.com/keymanapp/keyman.git Vcs-Browser: https://github.com/keymanapp/keyman Homepage: https://www.keyman.com From 63b8867aa40680940c789ae3009a74b1ac031d6c Mon Sep 17 00:00:00 2001 From: Darcy Date: Tue, 15 Mar 2022 09:54:00 +0700 Subject: [PATCH 39/46] chore(android): Separate CI step to generate Play Store notes --- android/KMAPro/build-play-store-notes.sh | 48 ++++++++++++++++++++++++ android/build-help.sh | 31 --------------- android/build-publish.sh | 3 ++ android/help/about/whatsnew.md | 2 +- 4 files changed, 52 insertions(+), 32 deletions(-) create mode 100755 android/KMAPro/build-play-store-notes.sh mode change 100644 => 100755 android/build-publish.sh diff --git a/android/KMAPro/build-play-store-notes.sh b/android/KMAPro/build-play-store-notes.sh new file mode 100755 index 0000000000..6ca9ca0e4b --- /dev/null +++ b/android/KMAPro/build-play-store-notes.sh @@ -0,0 +1,48 @@ +# Set sensible script defaults: +# set -e: Terminate script if a command returns an error +set -e +# set -u: Terminate script if an unset variable is used +set -u + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../resources/build/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +QUIET=0 + +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" + +THIS_DIR="$(dirname "$THIS_SCRIPT")" + +# +# Copy release notes for Gradle Play Publisher to upload +# Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes +# +PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/$TIER.txt" +if [ $TIER = "stable" ]; then + PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/default.txt" +fi +echo "Generating Play Store release notes to $PLAY_RELEASE_NOTES" +echo "" > "$PLAY_RELEASE_NOTES" + +# Copy whatsnew.md to release notes 1 line at a time, +# filtering for lines that start with "*". +# Play Store release notes have a limit of 500 characters +FILTERED_LINES=`grep '^\s*\*.*$' "$KEYMAN_ROOT/android/help/about/whatsnew.md"` +IFS=$'\n' # Change IFS to new line +for line in $FILTERED_LINES +do + CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) + CHARS_IN_CURRENT_LINE=$( wc -m <<< $line ) + if (( CHARS_IN_RELEASE_NOTES + CHARS_IN_CURRENT_LINE + 1 < 450 )); then + # Copy line to Play Store release notes + echo "$line" >> $PLAY_RELEASE_NOTES + else + # 450 chars reached + warn "Warning: Play Store release notes approaching 500 character limit" + echo '* Additional bug fixes and improvements' >> $PLAY_RELEASE_NOTES + break + fi +done diff --git a/android/build-help.sh b/android/build-help.sh index 2053c5fdcc..0b47159633 100755 --- a/android/build-help.sh +++ b/android/build-help.sh @@ -107,34 +107,3 @@ if $DO_HTM; then cp android_images/* "$DESTHTM/android_images/" fi - -# -# Copy release notes for Gradle Play Publisher to upload -# Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes -# -PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/$TIER.txt" -if [ $TIER = "stable" ]; then - PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/default.txt" -fi -echo "Generating Play Store release notes to $PLAY_RELEASE_NOTES" -echo "" > "$PLAY_RELEASE_NOTES" - -# Copy whatsnew.md to release notes 1 line at a time, -# filtering for lines that start with "*". -# Play Store release notes have a limit of 500 characters -FILTERED_LINES=`grep '^\s*\*.*$' "$KEYMAN_ROOT/android/help/about/whatsnew.md"` -IFS=$'\n' # Change IFS to new line -for line in $FILTERED_LINES -do - CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) - CHARS_IN_CURRENT_LINE=$( wc -m <<< $line ) - if (( CHARS_IN_RELEASE_NOTES + CHARS_IN_CURRENT_LINE + 1 < 450 )); then - # Copy line to Play Store release notes - echo "$line" >> $PLAY_RELEASE_NOTES - else - # 450 chars reached - warn "Warning: Play Store release notes approaching 500 character limit" - echo '* Additional bug fixes and improvements' >> $PLAY_RELEASE_NOTES - break - fi -done diff --git a/android/build-publish.sh b/android/build-publish.sh old mode 100644 new mode 100755 index 53dcd3a334..3cce36b910 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -75,6 +75,9 @@ echo "BUILD_FLAGS $BUILD_FLAGS" # Publish Keyman for Android if [ "$DO_KMAPRO" = true ]; then cd "$KEYMAN_ROOT/android/KMAPro/" + # Copy Release Notes + ./build-play-store-notes.sh + ./gradlew $DAEMON_FLAG $BUILD_FLAGS fi diff --git a/android/help/about/whatsnew.md b/android/help/about/whatsnew.md index 17331a0c77..9fe22293e9 100644 --- a/android/help/about/whatsnew.md +++ b/android/help/about/whatsnew.md @@ -15,6 +15,6 @@ Here are some of the new features we have added to Keyman 15.0 for Android: | System | 1 | Quickly switch to previous system keyboard | | System | 2+ | Quickly switch to next Keyman keyboard | - * Long press and release the globe key to bring up the keyboard picker menu. On a Keyman system keyboard, the bottom of this menu will also display other enabled system keyboards that can be selected. + * Long press the globe key to bring up the keyboard picker menu. On a Keyman system keyboard, the bottom of this menu will also display other enabled system keyboards that can be selected. Note: On the lock screen, the keyboard picker menu is not displayed. From 2e9e90dd7720ab70430d06f87517a5837fed3ac6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 15 Mar 2022 13:59:27 +1100 Subject: [PATCH 40/46] chore: license date --- LICENSE.md | 4 ++-- windows/src/LICENSE.md | 2 +- windows/src/desktop/help/about/license.md | 2 +- windows/src/desktop/inst/license.html | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 24c907d61f..e031c6cc13 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # License -Copyright (c) 2017-2021 SIL International. All rights reserved. +Copyright (c) 2017-2022 SIL International. All rights reserved. Licensed under the MIT License. @@ -10,7 +10,7 @@ Licensed under the MIT License. The MIT License -Copyright (c) 2017-2021 SIL International +Copyright (c) 2017-2022 SIL International Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/windows/src/LICENSE.md b/windows/src/LICENSE.md index 03ccd799e4..b7d688870a 100644 --- a/windows/src/LICENSE.md +++ b/windows/src/LICENSE.md @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2017-2021 SIL International +Copyright (c) 2017-2022 SIL International Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/windows/src/desktop/help/about/license.md b/windows/src/desktop/help/about/license.md index 47f28d039b..b3d2e88414 100644 --- a/windows/src/desktop/help/about/license.md +++ b/windows/src/desktop/help/about/license.md @@ -4,7 +4,7 @@ title: End User Licence and Services Agreement The MIT License -Copyright (c) 2017-2021 SIL International +Copyright (c) 2017-2022 SIL International Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/windows/src/desktop/inst/license.html b/windows/src/desktop/inst/license.html index 1dd4ee0399..e6bc9dc16e 100644 --- a/windows/src/desktop/inst/license.html +++ b/windows/src/desktop/inst/license.html @@ -13,7 +13,7 @@

The MIT License

-

Copyright (c) 2017-2021 SIL International

+

Copyright (c) 2017-2022 SIL International

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2c1b1555702ca68bce7e93beb4e9fe98cc3ff7b7 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 15 Mar 2022 10:30:50 +0100 Subject: [PATCH 41/46] chore(linux): Address a few more lintian warnings --- .editorconfig | 3 +- linux/debian/copyright | 111 +++++++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 44 deletions(-) diff --git a/.editorconfig b/.editorconfig index f68c86a948..99552fac20 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,8 +9,7 @@ insert_final_newline = true trim_trailing_whitespace = true [*.md] -# Lintian in Debian complains about lines > 512 -max_line_length = 512 +max_line_length = 160 [{Makefile,rules}] indent_style = tab diff --git a/linux/debian/copyright b/linux/debian/copyright index e7bb6aadc1..5c7c5e9189 100644 --- a/linux/debian/copyright +++ b/linux/debian/copyright @@ -5,7 +5,7 @@ Source: https://github.com/keymanapp/keyman Files: * Copyright: 2018-2022 SIL International -License: Expat +License: MIT Files: linux/ibus-keyman/* Copyright: 2004-2022 SIL International @@ -16,7 +16,7 @@ Files: linux/ibus-keyman/src/keymanutil.c linux/ibus-keyman/src/kmpdetails.c linux/ibus-keyman/src/kmpdetails.h Copyright: 2009-2022 SIL International -License: GPL-2+ or Expat +License: GPL-2+ or MIT Files: linux/ibus-keyman/src/keyman-service.c linux/ibus-keyman/src/keyman-service.h @@ -30,72 +30,77 @@ Copyright: 1996-2003, 2009-2015, Free Software Foundation, Inc. License: FSFULLR Files: linux/ibus-keyman/Makefile.am - linux/ibus-keyman/Makefile.in - linux/ibus-keyman/compile - linux/ibus-keyman/configure.ac - linux/ibus-keyman/depcomp - linux/ibus-keyman/m4/Makefile.am - linux/ibus-keyman/m4/Makefile.in - linux/ibus-keyman/missing - linux/ibus-keyman/src/Makefile.am - linux/ibus-keyman/src/Makefile.in - linux/ibus-keyman/src/engine.c - linux/ibus-keyman/src/engine.h - linux/ibus-keyman/src/main.c - linux/ibus-keyman/src/test/Makefile.am - linux/ibus-keyman/src/test/Makefile.in - linux/ibus-keyman/tap-driver.sh - linux/ibus-keyman/test-driver - linux/ibus-keyman/tests/Makefile.am - linux/ibus-keyman/tests/Makefile.in + linux/ibus-keyman/Makefile.in + linux/ibus-keyman/compile + linux/ibus-keyman/configure.ac + linux/ibus-keyman/depcomp + linux/ibus-keyman/m4/Makefile.am + linux/ibus-keyman/m4/Makefile.in + linux/ibus-keyman/missing + linux/ibus-keyman/src/Makefile.am + linux/ibus-keyman/src/Makefile.in + linux/ibus-keyman/src/engine.c + linux/ibus-keyman/src/engine.h + linux/ibus-keyman/src/main.c + linux/ibus-keyman/src/test/Makefile.am + linux/ibus-keyman/src/test/Makefile.in + linux/ibus-keyman/tap-driver.sh + linux/ibus-keyman/test-driver + linux/ibus-keyman/tests/Makefile.am + linux/ibus-keyman/tests/Makefile.in Copyright: 1994-2017, Free Software Foundation, Inc. - 2009-2022, SIL International + 2009-2022, SIL International License: GPL-2+ Files: linux/ibus-keyman/m4/gettext.m4 - linux/ibus-keyman/m4/intl.m4 - linux/ibus-keyman/m4/intldir.m4 - linux/ibus-keyman/m4/intlmacosx.m4 - linux/ibus-keyman/m4/lcmessage.m4 - linux/ibus-keyman/m4/nls.m4 - linux/ibus-keyman/m4/po.m4 - linux/ibus-keyman/m4/progtest.m4 -Copyright: 1995--2014, Free Software Foundation, Inc. -License: FSFULLR and/or GPL-3 and/or LGPL-3 + linux/ibus-keyman/m4/intl.m4 + linux/ibus-keyman/m4/intldir.m4 + linux/ibus-keyman/m4/intlmacosx.m4 + linux/ibus-keyman/m4/lcmessage.m4 + linux/ibus-keyman/m4/nls.m4 + linux/ibus-keyman/m4/po.m4 + linux/ibus-keyman/m4/progtest.m4 +Copyright: 1995-2014, Free Software Foundation, Inc. +License: FSFULLR or GPL-3 or LGPL-3 Files: linux/ibus-keyman/install-sh - linux/keyman-config/COPYING Copyright: 1994, X Consortium - 2018, SIL International -License: Expat + 2018, SIL International +License: MIT Files: linux/ibus-keyman/INSTALL - linux/ibus-keyman/po/Makefile.in.in + linux/ibus-keyman/po/Makefile.in.in Copyright: 1994-1996, 1999-2002, 2004-2016, Free Software Foundation, Inc. - 1995-1997, 2000-2007, 2009-2010, Ulrich Drepper + 1995-1997, 2000-2007, 2009-2010, Ulrich Drepper License: FSFAP Files: linux/ibus-keyman/icons/Makefile.am linux/ibus-keyman/icons/Makefile.in Copyright: 1994-2017, Free Software Foundation, Inc. - 2018, SIL International + 2018, SIL International License: LGPL-2+ Files: linux/ibus-keyman/tests/ibusimcontext.c linux/ibus-keyman/tests/ibusimcontext.h Copyright: 2008-2010, Peng Huang - 2008-2010, Red Hat, Inc. - 2008-2013, Peng Huang - 2008-2021, Red Hat, Inc. - 2015-2021, Takao Fujiwara - 2021-2022, SIL International + 2008-2010, Red Hat, Inc. + 2008-2013, Peng Huang + 2008-2021, Red Hat, Inc. + 2015-2021, Takao Fujiwara + 2021-2022, SIL International License: LGPL-2.1+ Files: linux/keyman-config/buildtools/help2man Copyright: 1997-2005, 2009-2017, 2020-2021, Free Software Foundation, Inc. License: GPL-3+ -License: Expat +Files: debian/com.keyman.config.appdata.xml + debian/com.keyman.ibus_keyman.metainfo.xml +Copyright: 2019 Daniel Glassey + 2022 SIL International +License: MIT + +License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including @@ -134,6 +139,24 @@ License: GPL-2+ License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. +License: GPL-3 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 3. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 3 can be found in the file + `/usr/share/common-licenses/GPL-3'. + License: GPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -200,3 +223,7 @@ License: LGPL-2.1+ On Debian systems, the full text of the GNU Lesser General Public License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. + +License: LGPL-3 + On Debian systems, the full text of the GNU Lesser General Public + License version 3 can be found in `/usr/share/common-licenses/LGPL-3'. From 0c78e44eda54e69c19da6665d9b4166f6c38f948 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 15 Mar 2022 17:53:46 +0100 Subject: [PATCH 42/46] chore(linux): Remove debug output --- linux/keyman-config/keyman_config/ibus_util.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/linux/keyman-config/keyman_config/ibus_util.py b/linux/keyman-config/keyman_config/ibus_util.py index e335f80a32..1e992d7aa8 100644 --- a/linux/keyman-config/keyman_config/ibus_util.py +++ b/linux/keyman-config/keyman_config/ibus_util.py @@ -80,7 +80,6 @@ def restart_ibus_subp(): def verify_ibus_daemon(start): - logging.info('**** Verify ibus running') realuser = os.environ.get('SUDO_USER') user = os.environ.get('USER') if realuser: @@ -90,8 +89,6 @@ def verify_ibus_daemon(start): try: ps = subprocess.run(('ps', '--user', user, '-o', 's=', '-o', 'cmd'), stdout=subprocess.PIPE).stdout - debugps = subprocess.run(('bash', '-c', 'ps -ef | grep ibus-daemon'), stdout=subprocess.PIPE).stdout - logging.info('**** running processes: %s', debugps.decode('utf-8')) ibus_daemons = re.findall('^[^ZT] ibus-daemon .*--xim.*', ps.decode('utf-8'), re.MULTILINE) if len(ibus_daemons) <= 0: if start: @@ -100,7 +97,7 @@ def verify_ibus_daemon(start): logging.error('More than one ibus-daemon instance running! Keyman keyboards might not work as expected. ' 'Please reboot your machine.') else: - logging.info('ibus already running') + logging.debug('ibus already running') except subprocess.CalledProcessError as e: # Log critical error in order to track down #6237 logging.critical('getting ibus-daemon failed (%s: %s)', type(e), e.args) From ed5dd2f2bdc4c7a53a57bbcc55257bfe741077fc Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Tue, 15 Mar 2022 14:31:13 -0400 Subject: [PATCH 43/46] auto: increment beta version to 15.0.214 --- HISTORY.md | 13 ++++++++++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- developer/server/package-lock.json | 2 +- developer/server/package.json | 2 +- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 31 files changed, 84 insertions(+), 71 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 417daa0d3f..4757c76cc1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,18 @@ # Keyman Version History +## 15.0.213 beta 2022-03-15 + +* feat(common): zip and index keyboard artifacts (#6367) +* fix(android/engine): Activate menu on globe longpress before release (#6356) +* fix(web): subkey touch position after scroll (#6340) +* fix(developer): warn on ncaps usage inconsistency (#6347) +* fix(web): caps state tracking for touch (#6351) +* chore(windows): Update license date (#6374) +* chore(android): Separate CI step to generate Play Store notes (#6375) +* chore(linux): Update changelog and copyright (#6372) +* fix(oem/fv/android): Consolidate dictionary and keyboard settings (#6369) +* fix(linux): Don't start ibus-daemon multiple times (#6283) + ## 15.0.212 beta 2022-03-11 * chore(linux): Fix lintian warnings (#6360) diff --git a/VERSION.md b/VERSION.md index 2f56ef3079..9cbae34018 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.213 \ No newline at end of file +15.0.214 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 6e5e60d4be..1749843b91 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index cb2be22a31..5275a9f17a 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.213", + "version": "15.0.214", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.213", - "@keymanapp/resources-gosh": "^15.0.213", + "@keymanapp/lexical-model-compiler": "^15.0.214", + "@keymanapp/resources-gosh": "^15.0.214", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.213", - "@keymanapp/lexical-model-layer": "^15.0.213", - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/keyboard-processor": "^15.0.214", + "@keymanapp/lexical-model-layer": "^15.0.214", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index c9dc4a3ce2..59da84fb26 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 90f123201a..c44b4ab1d5 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.213", + "version": "15.0.214", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.213", + "@keymanapp/resources-gosh": "^15.0.214", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index ccf01236fc..02a946eb54 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index b97900f6a3..029c14ee9c 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.213", + "version": "15.0.214", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.213", - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/keyboard-processor": "^15.0.214", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index 9c008a4c53..dc70800059 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index 50c5bcd3c1..54a116dceb 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.213", + "version": "15.0.214", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/web-environment": "^15.0.214", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index c7274e8009..463c658434 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index 556a8b20f4..ae1ef99074 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.213", + "version": "15.0.214", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", + "@keymanapp/resources-gosh": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index d568a67559..7c0ad2af3e 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 145e210afa..28dc0a40ac 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.213", + "version": "15.0.214", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.213" + "@keymanapp/models-wordbreakers": "^15.0.214" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index b98c5749cf..37ae0ea3a2 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 50eb31ee8f..1543ca45bd 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.213", + "version": "15.0.214", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index cf8043a3c2..c07dad8406 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index 390e5d912e..839b3531b4 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.213", + "version": "15.0.214", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.213", + "@keymanapp/models-types": "^15.0.214", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 8dc2a719bf..91bcd1e49d 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index c9a8b36799..cbbe00af00 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.213", + "version": "15.0.214", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/resources-gosh": "^15.0.213", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/resources-gosh": "^15.0.214", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.213", - "@keymanapp/models-wordbreakers": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/models-templates": "^15.0.214", + "@keymanapp/models-wordbreakers": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index 1b0dc2ed16..e981fb2f20 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index aa013907b7..1360d46654 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.213", + "version": "15.0.214", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.213", + "@keymanapp/models-types": "^15.0.214", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.213", - "@keymanapp/models-wordbreakers": "^15.0.213", + "@keymanapp/models-templates": "^15.0.214", + "@keymanapp/models-wordbreakers": "^15.0.214", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/developer/server/package-lock.json b/developer/server/package-lock.json index 0e1cb3a2b3..dc60277759 100644 --- a/developer/server/package-lock.json +++ b/developer/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/server/package.json b/developer/server/package.json index 9e44f11840..6f5db5734b 100644 --- a/developer/server/package.json +++ b/developer/server/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.213", + "version": "15.0.214", "description": "Keyman Developer backend server", "main": "dist/index.js", "scripts": { diff --git a/lerna.json b/lerna.json index ba04cf6243..820c34d23a 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "ts-node", "typescript" ], - "version": "15.0.213" + "version": "15.0.214" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 64ea9292c0..576aba53a7 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index e4c9d0d75b..5dfaa7713e 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.213", + "version": "15.0.214", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index cc5107ea79..96f568a730 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 04124b39ea..d30c2e1885 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.213", + "version": "15.0.214", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.213" + "@keymanapp/resources-gosh": "^15.0.214" } } diff --git a/web/package-lock.json b/web/package-lock.json index 0ed0ee5075..30cd6c7e74 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.213", + "version": "15.0.214", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index b62b228b4a..b00bc25224 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.213", + "version": "15.0.214", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.213", - "@keymanapp/web-sentry-manager": "^15.0.213", + "@keymanapp/resources-gosh": "^15.0.214", + "@keymanapp/web-sentry-manager": "^15.0.214", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.213", - "@keymanapp/keyboard-processor": "^15.0.213", - "@keymanapp/lexical-model-layer": "^15.0.213", - "@keymanapp/models-types": "^15.0.213", - "@keymanapp/recorder-core": "^15.0.213", - "@keymanapp/web-environment": "^15.0.213", - "@keymanapp/web-utils": "^15.0.213", + "@keymanapp/input-processor": "^15.0.214", + "@keymanapp/keyboard-processor": "^15.0.214", + "@keymanapp/lexical-model-layer": "^15.0.214", + "@keymanapp/models-types": "^15.0.214", + "@keymanapp/recorder-core": "^15.0.214", + "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-utils": "^15.0.214", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From a595b63422d819ad6be3d1c2b8cb83eef881967e Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 16 Mar 2022 14:30:41 -0400 Subject: [PATCH 44/46] auto: increment beta version to 15.0.215 --- HISTORY.md | 4 ++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- developer/server/package-lock.json | 2 +- developer/server/package.json | 2 +- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 31 files changed, 75 insertions(+), 71 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 4757c76cc1..31dcb53eae 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ # Keyman Version History +## 15.0.214 beta 2022-03-16 + +* feat(web): `&newLayer` and `&oldLayer` (#6366) + ## 15.0.213 beta 2022-03-15 * feat(common): zip and index keyboard artifacts (#6367) diff --git a/VERSION.md b/VERSION.md index 9cbae34018..c57f95eee4 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.214 \ No newline at end of file +15.0.215 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 1749843b91..00b0915e39 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 5275a9f17a..2e60eadbc5 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.214", + "version": "15.0.215", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.214", - "@keymanapp/resources-gosh": "^15.0.214", + "@keymanapp/lexical-model-compiler": "^15.0.215", + "@keymanapp/resources-gosh": "^15.0.215", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.214", - "@keymanapp/lexical-model-layer": "^15.0.214", - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/keyboard-processor": "^15.0.215", + "@keymanapp/lexical-model-layer": "^15.0.215", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index 59da84fb26..026c9679a7 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index c44b4ab1d5..07a12df0d4 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.214", + "version": "15.0.215", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.214", + "@keymanapp/resources-gosh": "^15.0.215", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index 02a946eb54..62937b778b 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index 029c14ee9c..5c78b083f0 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.214", + "version": "15.0.215", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.214", - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/keyboard-processor": "^15.0.215", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index dc70800059..91d5efd68d 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index 54a116dceb..ff8861cae1 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.214", + "version": "15.0.215", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/web-environment": "^15.0.215", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index 463c658434..df15cc11ea 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index ae1ef99074..aff3f68775 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.214", + "version": "15.0.215", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", + "@keymanapp/resources-gosh": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 7c0ad2af3e..72becbda23 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 28dc0a40ac..0d45711472 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.214", + "version": "15.0.215", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.214" + "@keymanapp/models-wordbreakers": "^15.0.215" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 37ae0ea3a2..955428ce54 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 1543ca45bd..ee047c0861 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.214", + "version": "15.0.215", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index c07dad8406..fe8ac412aa 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index 839b3531b4..27a7e6d10d 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.214", + "version": "15.0.215", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.214", + "@keymanapp/models-types": "^15.0.215", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 91bcd1e49d..7d5c8b3496 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index cbbe00af00..43ab4bcbc3 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.214", + "version": "15.0.215", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/resources-gosh": "^15.0.214", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/resources-gosh": "^15.0.215", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.214", - "@keymanapp/models-wordbreakers": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/models-templates": "^15.0.215", + "@keymanapp/models-wordbreakers": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index e981fb2f20..55525b99eb 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index 1360d46654..bafef06286 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.214", + "version": "15.0.215", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.214", + "@keymanapp/models-types": "^15.0.215", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.214", - "@keymanapp/models-wordbreakers": "^15.0.214", + "@keymanapp/models-templates": "^15.0.215", + "@keymanapp/models-wordbreakers": "^15.0.215", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/developer/server/package-lock.json b/developer/server/package-lock.json index dc60277759..d5758a4c71 100644 --- a/developer/server/package-lock.json +++ b/developer/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/server/package.json b/developer/server/package.json index 6f5db5734b..dec0cff74b 100644 --- a/developer/server/package.json +++ b/developer/server/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.214", + "version": "15.0.215", "description": "Keyman Developer backend server", "main": "dist/index.js", "scripts": { diff --git a/lerna.json b/lerna.json index 820c34d23a..328cd484ee 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "ts-node", "typescript" ], - "version": "15.0.214" + "version": "15.0.215" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 576aba53a7..7c9e2b3ab3 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index 5dfaa7713e..f177b2fb0f 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.214", + "version": "15.0.215", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index 96f568a730..f78cdc7730 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index d30c2e1885..3dc8962997 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.214", + "version": "15.0.215", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.214" + "@keymanapp/resources-gosh": "^15.0.215" } } diff --git a/web/package-lock.json b/web/package-lock.json index 30cd6c7e74..1546735047 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.214", + "version": "15.0.215", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index b00bc25224..3fe974b299 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.214", + "version": "15.0.215", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.214", - "@keymanapp/web-sentry-manager": "^15.0.214", + "@keymanapp/resources-gosh": "^15.0.215", + "@keymanapp/web-sentry-manager": "^15.0.215", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.214", - "@keymanapp/keyboard-processor": "^15.0.214", - "@keymanapp/lexical-model-layer": "^15.0.214", - "@keymanapp/models-types": "^15.0.214", - "@keymanapp/recorder-core": "^15.0.214", - "@keymanapp/web-environment": "^15.0.214", - "@keymanapp/web-utils": "^15.0.214", + "@keymanapp/input-processor": "^15.0.215", + "@keymanapp/keyboard-processor": "^15.0.215", + "@keymanapp/lexical-model-layer": "^15.0.215", + "@keymanapp/models-types": "^15.0.215", + "@keymanapp/recorder-core": "^15.0.215", + "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-utils": "^15.0.215", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From e3537e7bb7e098b3e96f1e693b4eef4d59028694 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 17 Mar 2022 15:50:52 +1100 Subject: [PATCH 45/46] fix(web): crash on focus before init Fixes the following crash noted when testing on keymanweb.com, focusing during the load process on a slow network. ``` helpers.ts:111 Uncaught TypeError: Cannot read properties of null (reading 'vkbd') at g.pageFocusHandler (keymanweb.ts:125:44) at sentryWrapped (helpers.ts:87:17) ``` --- web/source/keymanweb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/source/keymanweb.ts b/web/source/keymanweb.ts index 79aa71ac58..61d523f6fa 100644 --- a/web/source/keymanweb.ts +++ b/web/source/keymanweb.ts @@ -122,7 +122,7 @@ if(!window['keyman']['initialized']) { **/ function resetVKShift() { let keyman = com.keyman.singleton; - if(!keyman.uiManager.isActivating && keyman.osk.vkbd) { + if(!keyman.uiManager.isActivating && keyman.osk?.vkbd) { keyman.core.keyboardProcessor._UpdateVKShift(null); //this should be enabled !!!!! TODO } } From cdc94f73b2b9349390b85e26e645d6bf2d963eaa Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 17 Mar 2022 14:03:41 -0400 Subject: [PATCH 46/46] auto: increment beta version to 15.0.216 --- HISTORY.md | 4 ++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- developer/server/package-lock.json | 2 +- developer/server/package.json | 2 +- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 31 files changed, 75 insertions(+), 71 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 31dcb53eae..df57d7815d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ # Keyman Version History +## 15.0.215 beta 2022-03-17 + +* fix(web): crash on focus before init (#6393) + ## 15.0.214 beta 2022-03-16 * feat(web): `&newLayer` and `&oldLayer` (#6366) diff --git a/VERSION.md b/VERSION.md index c57f95eee4..8b01078ed3 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.215 \ No newline at end of file +15.0.216 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 00b0915e39..53ee499c90 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 2e60eadbc5..d75de9055b 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.215", + "version": "15.0.216", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.215", - "@keymanapp/resources-gosh": "^15.0.215", + "@keymanapp/lexical-model-compiler": "^15.0.216", + "@keymanapp/resources-gosh": "^15.0.216", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.215", - "@keymanapp/lexical-model-layer": "^15.0.215", - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/keyboard-processor": "^15.0.216", + "@keymanapp/lexical-model-layer": "^15.0.216", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index 026c9679a7..fe44fb7853 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 07a12df0d4..347f838f6b 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.215", + "version": "15.0.216", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.215", + "@keymanapp/resources-gosh": "^15.0.216", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index 62937b778b..c44727da9a 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index 5c78b083f0..b12e1b6284 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.215", + "version": "15.0.216", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.215", - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/keyboard-processor": "^15.0.216", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index 91d5efd68d..a932f2a8d8 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index ff8861cae1..4f432b8ffc 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.215", + "version": "15.0.216", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/web-environment": "^15.0.216", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index df15cc11ea..f90dd640fe 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index aff3f68775..016e57bdb7 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.215", + "version": "15.0.216", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", + "@keymanapp/resources-gosh": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 72becbda23..aed3769f2c 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 0d45711472..f7fc5c69be 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.215", + "version": "15.0.216", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.215" + "@keymanapp/models-wordbreakers": "^15.0.216" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 955428ce54..8a5baf0b92 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index ee047c0861..78762c80d3 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.215", + "version": "15.0.216", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index fe8ac412aa..745b40eeed 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index 27a7e6d10d..f90fb38d59 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.215", + "version": "15.0.216", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.215", + "@keymanapp/models-types": "^15.0.216", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 7d5c8b3496..08ec16035f 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 43ab4bcbc3..b2b0df0192 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.215", + "version": "15.0.216", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/resources-gosh": "^15.0.215", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/resources-gosh": "^15.0.216", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.215", - "@keymanapp/models-wordbreakers": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/models-templates": "^15.0.216", + "@keymanapp/models-wordbreakers": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index 55525b99eb..7c5242c7ad 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index bafef06286..feb257b144 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.215", + "version": "15.0.216", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.215", + "@keymanapp/models-types": "^15.0.216", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.215", - "@keymanapp/models-wordbreakers": "^15.0.215", + "@keymanapp/models-templates": "^15.0.216", + "@keymanapp/models-wordbreakers": "^15.0.216", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/developer/server/package-lock.json b/developer/server/package-lock.json index d5758a4c71..d446541e4f 100644 --- a/developer/server/package-lock.json +++ b/developer/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/server/package.json b/developer/server/package.json index dec0cff74b..aa88108be2 100644 --- a/developer/server/package.json +++ b/developer/server/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/developer-server", - "version": "15.0.215", + "version": "15.0.216", "description": "Keyman Developer backend server", "main": "dist/index.js", "scripts": { diff --git a/lerna.json b/lerna.json index 328cd484ee..780730545e 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "ts-node", "typescript" ], - "version": "15.0.215" + "version": "15.0.216" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 7c9e2b3ab3..52c6bf6913 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index f177b2fb0f..88c1df00d1 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.215", + "version": "15.0.216", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index f78cdc7730..29b4be57ff 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 3dc8962997..001df8b36a 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.215", + "version": "15.0.216", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.215" + "@keymanapp/resources-gosh": "^15.0.216" } } diff --git a/web/package-lock.json b/web/package-lock.json index 1546735047..1e3873552f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.215", + "version": "15.0.216", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index 3fe974b299..b952160f48 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.215", + "version": "15.0.216", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.215", - "@keymanapp/web-sentry-manager": "^15.0.215", + "@keymanapp/resources-gosh": "^15.0.216", + "@keymanapp/web-sentry-manager": "^15.0.216", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.215", - "@keymanapp/keyboard-processor": "^15.0.215", - "@keymanapp/lexical-model-layer": "^15.0.215", - "@keymanapp/models-types": "^15.0.215", - "@keymanapp/recorder-core": "^15.0.215", - "@keymanapp/web-environment": "^15.0.215", - "@keymanapp/web-utils": "^15.0.215", + "@keymanapp/input-processor": "^15.0.216", + "@keymanapp/keyboard-processor": "^15.0.216", + "@keymanapp/lexical-model-layer": "^15.0.216", + "@keymanapp/models-types": "^15.0.216", + "@keymanapp/recorder-core": "^15.0.216", + "@keymanapp/web-environment": "^15.0.216", + "@keymanapp/web-utils": "^15.0.216", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0"