diff --git a/HISTORY.md b/HISTORY.md index 7d110e920d2..0c1646e28e8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,35 @@ # Keyman Version History +## 16.0.49 alpha 2022-08-22 + +* fix: remove saving and restoring context kbd options (#7077) +* chore(deps): bump @actions/core from 1.8.2 to 1.9.1 (#7087) + +## 16.0.48 alpha 2022-08-16 + +* fix(web): button, float init timer cleanup (#7036) + +## 16.0.47 alpha 2022-08-15 + +* chore(core): refactor kmx_file.h to common (#7062) +* fix(developer): stack overflow when compiling non-web keyboard (#7031) +* fix(developer): prevent crash attempting to compile ansi keyboard (#7033) +* chore(linux): Refactor `jenkins.sh` (#7060) +* fix(developer): compiler emitting garbage for readonly groups (#7013) + +## 16.0.46 alpha 2022-08-12 + +* docs(core): cleanup in keyboardprocessor.h (#7065) + +## 16.0.45 alpha 2022-08-09 + +* feat(linux): Replace deprecated distutils (#7051) +* chore(linux): Adjust Linux source package to restructured code (#7056) + +## 16.0.44 alpha 2022-08-08 + +* chore(linux): Update debian changelog (#7041) + ## 16.0.43 alpha 2022-08-05 * chore(web): centralizes web-based modules' CI unit test configurations (#7024) diff --git a/VERSION.md b/VERSION.md index c99e566a459..245e8fdca3f 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -16.0.44 \ No newline at end of file +16.0.50 \ No newline at end of file diff --git a/common/include/km_types.h b/common/include/km_types.h new file mode 100644 index 00000000000..113647d3a0a --- /dev/null +++ b/common/include/km_types.h @@ -0,0 +1,65 @@ +#pragma once + +/* +#if defined(_WIN32) || defined(_WIN64) +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif +*/ + +#if defined(__LP64__) || defined(_LP64) +/* 64-bit, g++ */ +#define KMX_64BIT +#endif + +#if defined(_WIN64) && !defined(USE_64) +/* 64-bit, Windows */ +#define KMX_64BIT +#endif + +typedef uint32_t KMX_DWORD; +typedef int32_t KMX_BOOL; +typedef uint8_t KMX_BYTE; +typedef uint16_t KMX_WORD; + +#if defined(__cplusplus) +typedef char16_t km_kbp_cp; +typedef char32_t km_kbp_usv; +#else +typedef uint16_t km_kbp_cp; // code point +typedef uint32_t km_kbp_usv; // Unicode Scalar Value +#endif + +typedef km_kbp_cp KMX_WCHAR; // wc, 16-bit UNICODE character +typedef KMX_WCHAR *PKMX_WCHAR; + +typedef char KMX_CHAR; +typedef KMX_CHAR *PKMX_CHAR; + +typedef uint32_t KMX_UINT; + +typedef KMX_BYTE *PKMX_BYTE; +typedef KMX_WORD *PKMX_WORD; +typedef KMX_DWORD *PKMX_DWORD; + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +// Macros and types to support char16_t vs wchar_t depending on project + +#ifdef USE_CHAR16_T +#define lpuch(x) u ## x +typedef km_kbp_cp KMX_UCHAR; +#else +#define lpuch(x) L ## x +typedef wchar_t KMX_UCHAR; +#endif + +typedef KMX_UCHAR* KMX_PUCHAR; diff --git a/core/src/kmx/kmx_file.h b/common/include/kmx_file.h similarity index 98% rename from core/src/kmx/kmx_file.h rename to common/include/kmx_file.h index 0d34cc615a9..480077b22c1 100644 --- a/core/src/kmx/kmx_file.h +++ b/common/include/kmx_file.h @@ -5,11 +5,14 @@ #pragma once -#include "kmx_base.h" +#include +#ifdef KMN_KBP +// TODO: move this to a common namespace keyman::common::kmx_file or similar in the future namespace km { namespace kbp { namespace kmx { +#endif #define KMX_MAX_ALLOWED_FILE_SIZE (128 * 1024 * 1024) /* 128MB */ /* */ @@ -371,6 +374,8 @@ static_assert(sizeof(COMP_KEY) == KEYBOARDFILEKEY_SIZE, "COMP_KEY must be KEYBOA static_assert(sizeof(COMP_GROUP) == KEYBOARDFILEGROUP_SIZE, "COMP_GROUP must be KEYBOARDFILEGROUP_SIZE bytes"); static_assert(sizeof(COMP_KEYBOARD) == KEYBOARDFILEHEADER_SIZE, "COMP_KEYBOARD must be KEYBOARDFILEHEADER_SIZE bytes"); +#ifdef KMN_KBP } // namespace kmx } // namespace kbp } // namespace km +#endif \ No newline at end of file diff --git a/common/web/keyboard-processor/src/text/codes.ts b/common/web/keyboard-processor/src/text/codes.ts index 0ea17a07fc3..915ae7feed9 100644 --- a/common/web/keyboard-processor/src/text/codes.ts +++ b/common/web/keyboard-processor/src/text/codes.ts @@ -1,7 +1,7 @@ namespace com.keyman.text { export var Codes = { // Define Keyman Developer modifier bit-flags (exposed for use by other modules) - // Compare against /core/src/kmx/kmx_file.h. CTRL+F "#define LCTRLFLAG" to find the secton. + // Compare against /common/include/kmx_file.h. CTRL+F "#define LCTRLFLAG" to find the secton. modifierCodes: { "LCTRL":0x0001, // LCTRLFLAG "RCTRL":0x0002, // RCTRLFLAG diff --git a/common/windows/cpp/include/legacy_kmx_file.h b/common/windows/cpp/include/legacy_kmx_file.h index 120f87c6fa0..421f8a9d8f5 100644 --- a/common/windows/cpp/include/legacy_kmx_file.h +++ b/common/windows/cpp/include/legacy_kmx_file.h @@ -4,7 +4,7 @@ Name: legacy_kmx_file Copyright: Copyright (C) SIL International. Documentation: - Description: Describes .kmx binary format. To be replaced with Core's kmx_file.h + Description: Describes .kmx binary format. To be replaced with common/include/kmx_file.h Create Date: 4 Jan 2007 Modified Date: 24 Aug 2015 diff --git a/core/include/keyman/keyboardprocessor.h b/core/include/keyman/keyboardprocessor.h index 9509451e112..acd29576de5 100644 --- a/core/include/keyman/keyboardprocessor.h +++ b/core/include/keyman/keyboardprocessor.h @@ -110,13 +110,6 @@ extern "C" #endif // Basic types // -#if defined(__cplusplus) -typedef char16_t km_kbp_cp; -typedef char32_t km_kbp_usv; -#else -typedef uint16_t km_kbp_cp; // code point -typedef uint32_t km_kbp_usv; // Unicode Scalar Value -#endif typedef uint16_t km_kbp_virtual_key; // A virtual key code. typedef uint32_t km_kbp_status; // Status return code. @@ -650,7 +643,7 @@ undefined. The returned buffer uses UTF-8 encoding. - `KM_KBP_STATUS_INVALID_ARGUMENT`: If non-optional parameters are null. - `KM_KBP_STATUS_NO_MEM`: In the event an internal memory allocation fails. ##### Parameters: -- __opts__: An opaque pointer to a state object. +- __state__: An opaque pointer to a state object. - __buf__: A pointer to the buffer to place the C string containing the JSON document into, can be null. - __space__: A pointer to a size_t variable. This variable must contain the @@ -793,7 +786,7 @@ km_kbp_keyboard_get_key_list(km_kbp_keyboard const *keyboard, Free the allocated memory belonging to a keyboard key list previously returned by `km_kbp_keyboard_get_key_list`. ##### Parameters: -- __keyboard__: A pointer to the keyboard key list to be +- __key_list__: A pointer to the keyboard key list to be disposed of. ```c @@ -1127,10 +1120,6 @@ In the event the `state` pointer is null ##### Parameters: - __state__: A pointer to the opaque state object. -- __vk__: A virtual key to be processed. -- __modifier_state__: -The combinations of modifier keys set at the time key `vk` was pressed, bitmask -from the `km_kbp_modifier_state` enum. ```c */ diff --git a/core/include/keyman/keyboardprocessor_bits.h b/core/include/keyman/keyboardprocessor_bits.h index d844d4e2a69..03892a62afb 100644 --- a/core/include/keyman/keyboardprocessor_bits.h +++ b/core/include/keyman/keyboardprocessor_bits.h @@ -58,3 +58,12 @@ #define KMN_API _kmn_tag_fn(_kmn_import_flag) #define KMN_DEPRECATED_API _kmn_tag_fn(_kmn_deprecated_flag _kmn_and _kmn_import_flag) #endif + +#ifndef KMN_KBP +#define KMN_KBP +#endif +#ifndef USE_CHAR16_T +#define USE_CHAR16_T +#endif + +#include diff --git a/core/include/meson.build b/core/include/meson.build index b6211db0f22..f52ab00d5cf 100644 --- a/core/include/meson.build +++ b/core/include/meson.build @@ -6,5 +6,5 @@ # History: 6 Oct 2018 - TSE - Move into keyman folder. # -inc = include_directories('.', is_system: true) +inc = include_directories('.', '../../common/include', is_system: true) subdir('keyman') diff --git a/core/meson.build b/core/meson.build index ed5e33bdbbf..cad35decec2 100644 --- a/core/meson.build +++ b/core/meson.build @@ -37,6 +37,10 @@ message('compiler.get_id(): ' + compiler.get_id()) cc = meson.get_compiler('c') +# TODO: Shared includes may use namespaces, etc which need future tidyup. +# For now, we use KMN_KBP to inject the km::kbp::kmx namespace +defns = ['-DKMN_KBP'] + subdir('doc') subdir('include') subdir('src') diff --git a/core/python/keyman/keyboardprocessor/_api.py b/core/python/keyman/keyboardprocessor/_api.py deleted file mode 100644 index 590910c0e4a..00000000000 --- a/core/python/keyman/keyboardprocessor/_api.py +++ /dev/null @@ -1,580 +0,0 @@ -# Copyright: © 2018 SIL International. -# Description: Lowlevel C style python API. Intended to be wrapped by a more -# Pythonic higher level API. -# Create Date: 18 Oct 2018 -# Authors: Tim Eves (TSE) -# - -import ctypes -import ctypes.util -import operator -import os -from enum import auto, IntEnum, IntFlag -from ctypes import (c_uint8, - c_uint16, c_uint32, - c_size_t, - c_void_p, c_char_p, - Structure, Union, POINTER, CFUNCTYPE) -from typing import Any, Tuple - -CP = c_uint16 -USV = c_uint32 -VirtualKey = c_uint16 - -libpath = os.environ.get('PYKMNKBD_LIBRARY_PATH', - ctypes.util.find_library("kmnkbp0")) - -libkbp = ctypes.cdll.LoadLibrary(libpath) - - -# Error handling -# ============== -class StatusCode(IntEnum): - OK = 0 - NO_MEM = auto() - IO_ERROR = auto() - INVALID_ARGUMENT = auto() - KEY_ERROR = auto() - OS_ERROR = 0x80000000 - - -Status = c_uint32 - - -def __map_oserror(code: Status) -> str: - code = StatusCode.OS_ERROR ^ code - msg = '{0!s}: OS error code (' + code + '): ' + os.strerror(code) - return msg, lambda m: OSError(code, m) - - -__exceptions_map = [ - (None, '{0!s}: Success'), - (MemoryError, '{0!s}: memory allocation failed.'), - (RuntimeError, '{0!s}: IO Error: {1!s}'), - (ValueError, '{0!s}: Invalid argument passed.'), - (LookupError, '{0!s}: Item does not exist in: {1!s}'), - (OSError, __map_oserror)] - - -def status_code(code: Status, func, args): - if code == StatusCode.OK: return args - exc, msg = __exceptions_map[code] - if callable(msg): msg = msg(code) - raise exc(msg.format(libkbp._name, *args)) - - -def null_check(code, func, args): - if code is not None: return args - raise KeyError(args[1] + ': Not found in collection') - - -class Dir(IntFlag): - IN = auto() - OUT = auto() - OPT = auto() - - -def __method(iface: str, method: str, result, - *args: Tuple[Any, Dir, str], **kwds): - proto = CFUNCTYPE(result, *map(operator.itemgetter(0), args)) - params = tuple(a[1:] for a in args) - c_name = iface+'_'+method if iface else method - f = proto(('km_kbp_' + c_name, libkbp), params) - if 'errcheck' in kwds: f.errcheck = kwds.get('errcheck') - globals()[c_name] = f - - -# Context processing -# ================== -Context_p = c_void_p - - -class ContextType(IntEnum): - END = 0 - CHAR = auto() - MARKER = auto() - - -class ContextItem(Structure): - class __ContextValue(Union): - _fields_ = (('character', USV), - ('marker', c_uint32)) - _anonymous_ = ('value',) - _fields_ = (('type', c_uint8), - ('value', __ContextValue)) - - -__method('context_items', 'from_utf16', Status, - (c_void_p, Dir.IN, 'text'), - (POINTER(POINTER(ContextItem)), Dir.OUT, 'context_items'), - errcheck=status_code) - -__method('context_items', 'to_utf16', c_size_t, - (POINTER(ContextItem), Dir.IN, 'context_items'), - (c_void_p, Dir.IN | Dir.OPT, 'buffer'), - (c_size_t, Dir.IN | Dir.OPT, 'buffer_size')) - -__method('context_items', 'dispose', None, - (POINTER(ContextItem), Dir.IN, 'context_items')) - -__method('context', 'set', Status, - (Context_p, Dir.IN, 'context'), - (POINTER(ContextItem), Dir.IN, 'context_items'), - errcheck=status_code) - -__method('context', 'get', POINTER(ContextItem), - (Context_p, Dir.IN, 'context')) - -__method('context', 'clear', None, (Context_p, Dir.IN, 'context')) - -__method('context', 'length', c_size_t, (Context_p, Dir.IN, 'context')) - -__method('context', 'append', Status, - (Context_p, Dir.IN, 'context'), - (POINTER(ContextItem), Dir.IN, 'context_items'), - errcheck=status_code) - -__method('context', 'shrink', Status, - (Context_p, Dir.IN, 'context'), - (c_size_t, Dir.IN, 'num'), - (POINTER(ContextItem), Dir.IN, 'prefix'), - errcheck=status_code) - - -class ActionItem(Structure): - class __ActionItem(Union): - _fields_ = (('marker', c_size_t), - ('option', c_char_p), - ('character', USV), - ('vkey', VirtualKey)) - _anonymous_ = ('data',) - _fields_ = (('type', c_uint8), - ('reserved', c_uint8*3), - ('data', __ActionItem)) - - -class ActionType(IntEnum): - END = 0 # Marks end of action items list. - CHAR = 1 - MARKER = 2 # correlates to kmn's "deadkey" markers - ALERT = 3 - BACK = 4 - PERSIST_OPT = 5 - RESET_OPT = 6 - VKEYDOWN = 7 - VKEYUP = 8 - VSHIFTDOWN = 9 - VSHIFTUP = 10 - MAX_TYPE_ID = auto() - - -# Option processing -# ================= -OptionSet_p = c_void_p - - -class OptionScope(IntEnum): - UNKNOWN = auto() - KEYBOARD = auto() - ENVIRONMENT = auto() - - -class Option(Structure): - _fields_ = (('key', c_char_p), - ('value', c_char_p), - ('scope', c_uint8)) - - -Option.END = Option(None, None) - -__method('options_set', 'size', c_size_t, (OptionSet_p, Dir.IN, 'opts')) - -__method('options_set', 'lookup', POINTER(Option), - (OptionSet_p, Dir.IN, 'opts'), - (c_char_p, Dir.IN, 'key'), - errcheck=null_check) - -__method('options_set', 'update', Status, - (OptionSet_p, Dir.IN, 'opts'), - (POINTER(Option), Dir.IN, 'new_opts'), - errcheck=status_code) - -__method('options_set', 'to_json', Status, - (OptionSet_p, Dir.IN, 'opts'), - (c_char_p, Dir.IN | Dir.OPT, 'buffer'), - (c_size_t, Dir.IN | Dir.OUT, 'space'), - errcheck=status_code) - - -# Keyboards -# ========= -Keyboard_p = c_void_p - - -class KeyboardAttrs(Structure): - _fields_ = (('version_string', c_char_p), - ('id', c_char_p), - ('folder_path', c_char_p), - ('default_options', OptionSet_p)) - - -__method('keyboard', 'load', Status, - (c_char_p, Dir.IN, 'path'), - (POINTER(Keyboard_p), Dir.OUT, 'kb'), - errcheck=status_code) - -__method('keyboard', 'dispose', None, (Keyboard_p, Dir.IN, 'kb')) - -__method('keyboard', 'get_attrs', POINTER(KeyboardAttrs), - (Keyboard_p, Dir.IN, 'keyboard')) - - -# State processing -# ================ -State_p = c_void_p - -__method('state', 'create', Status, - (Keyboard_p, Dir.IN, 'keyboard'), - (POINTER(Option), Dir.IN, 'env',), - (POINTER(State_p), Dir.OUT, 'out'), - errcheck=status_code) - -__method('state', 'clone', Status, - (State_p, Dir.IN, 'state'), - (POINTER(State_p), Dir.OUT, 'out'), - errcheck=status_code) - -__method('state', 'dispose', None, (State_p, Dir.IN, 'state')) - -__method('state', 'context', Context_p, (State_p, Dir.IN, 'state')) - -__method('state', 'options', OptionSet_p, (State_p, Dir.IN, 'state')) - -__method('state', 'action_items', POINTER(ActionItem), - (State_p, Dir.IN, 'state'), - (POINTER(c_size_t), Dir.OUT, 'num_items')) - -__method('state', 'to_json', Status, - (State_p, Dir.IN, 'state'), - (c_char_p, Dir.IN | Dir.OPT, 'buffer'), - (c_size_t, Dir.IN | Dir.OUT, 'space'), - errcheck=status_code) - - -# Processor -# ========= -class Attributes(Structure): - _fields_ = (('max_context', c_size_t), - ('current', c_uint16), - ('revision', c_uint16), - ('age', c_uint16), - ('technology', c_uint16), - ('vendor', c_char_p)) - - -class Tech(IntFlag): - UNSPECIFIED = 0 - KMN = 1 - LDML = 2 - -class EventFlag(IntFlag): - KM_KBP_EVENT_FLAG_DEFAULT = 0 - """default value: hardware""" - KM_KBP_EVENT_FLAG_TOUCH = 1 - """set if the event is touch, otherwise hardware""" - - -__method(None, 'get_engine_attrs', POINTER(Attributes)) - -__method(None, 'process_event', Status, - (State_p, Dir.IN, 'state'), - (VirtualKey, Dir.IN, 'vkey'), - (c_uint16, Dir.IN, 'modifier_state'), - (c_uint16, Dir.IN, 'event_flags')) - - -class Modifier(IntFlag): - LCTRL = 1 << 0 - RCTRL = 1 << 1 - LALT = 1 << 2 - RALT = 1 << 3 - SHIFT = 1 << 4 - CTRL = 1 << 5 - ALT = 1 << 6 - CAPS = 1 << 7 - NOCAPS = 1 << 8 - NUMLOCK = 1 << 9 - NONUMLOCK = 1 << 10 - SCROLLOCK = 1 << 11 - NOSCROLLOCK = 1 << 12 - VIRTUALKEY = 1 << 13 - - -class ModifierMask(IntFlag): - ALL = 0x7f - ALT_GR_SIM = Modifier.LCTRL | Modifier.LALT - CHIRAL = 0x1f - IS_CHIRAL = 0x0f - NON_CHIRAL = 0x7f - CAPS = 0x0300 - NUMLOCK = 0x0C00 - SCROLLLOCK = 0x3000 - - -class VKey(IntEnum): - _00 = auto() - LBUTTON = auto() - RBUTTON = auto() - CANCEL = auto() - MBUTTON = auto() - _05 = auto() - _06 = auto() - _07 = auto() - BKSP = auto() - KTAB = auto() - _0A = auto() - _0B = auto() - KP5 = auto() - ENTER = auto() - _0E = auto() - _0F = auto() - SHIFT = auto() - CONTROL = auto() - ALT = auto() - PAUSE = auto() - CAPS = auto() - _15 = auto() - _16 = auto() - _17 = auto() - _18 = auto() - _19 = auto() - _1A = auto() - ESC = auto() - _1C = auto() - _1D = auto() - _1E = auto() - _1F = auto() - SPACE = auto() - PGUP = auto() - PGDN = auto() - END = auto() - HOME = auto() - LEFT = auto() - UP = auto() - RIGHT = auto() - DOWN = auto() - SEL = auto() - PRINT = auto() - EXEC = auto() - PRTSCN = auto() - INS = auto() - DEL = auto() - HELP = auto() - K0 = auto() - K1 = auto() - K2 = auto() - K3 = auto() - K4 = auto() - K5 = auto() - K6 = auto() - K7 = auto() - K8 = auto() - K9 = auto() - _3A = auto() - _3B = auto() - _3C = auto() - _3D = auto() - _3E = auto() - _3F = auto() - _40 = auto() - KA = auto() - KB = auto() - KC = auto() - KD = auto() - KE = auto() - KF = auto() - KG = auto() - KH = auto() - KI = auto() - KJ = auto() - KK = auto() - KL = auto() - KM = auto() - KN = auto() - KO = auto() - KP = auto() - KQ = auto() - KR = auto() - KS = auto() - KT = auto() - KU = auto() - KV = auto() - KW = auto() - KX = auto() - KY = auto() - KZ = auto() - _5B = auto() - _5C = auto() - _5D = auto() - _5E = auto() - _5F = auto() - NP0 = auto() - NP1 = auto() - NP2 = auto() - NP3 = auto() - NP4 = auto() - NP5 = auto() - NP6 = auto() - NP7 = auto() - NP8 = auto() - NP9 = auto() - NPSTAR = auto() - NPPLUS = auto() - SEPARATOR = auto() - NPMINUS = auto() - NPDOT = auto() - NPSLASH = auto() - F1 = auto() - F2 = auto() - F3 = auto() - F4 = auto() - F5 = auto() - F6 = auto() - F7 = auto() - F8 = auto() - F9 = auto() - F10 = auto() - F11 = auto() - F12 = auto() - F13 = auto() - F14 = auto() - F15 = auto() - F16 = auto() - F17 = auto() - F18 = auto() - F19 = auto() - F20 = auto() - F21 = auto() - F22 = auto() - F23 = auto() - F24 = auto() - _88 = auto() - _89 = auto() - _8A = auto() - _8B = auto() - _8C = auto() - _8D = auto() - _8E = auto() - _8F = auto() - NUMLOCK = auto() - SCROLL = auto() - _92 = auto() - _93 = auto() - _94 = auto() - _95 = auto() - _96 = auto() - _97 = auto() - _98 = auto() - _99 = auto() - _9A = auto() - _9B = auto() - _9C = auto() - _9D = auto() - _9E = auto() - _9F = auto() - _A0 = auto() - _A1 = auto() - _A2 = auto() - _A3 = auto() - _A4 = auto() - _A5 = auto() - _A6 = auto() - _A7 = auto() - _A8 = auto() - _A9 = auto() - _AA = auto() - _AB = auto() - _AC = auto() - _AD = auto() - _AE = auto() - _AF = auto() - _B0 = auto() - _B1 = auto() - _B2 = auto() - _B3 = auto() - _B4 = auto() - _B5 = auto() - _B6 = auto() - _B7 = auto() - _B8 = auto() - _B9 = auto() - COLON = auto() - EQUAL = auto() - COMMA = auto() - HYPHEN = auto() - PERIOD = auto() - SLASH = auto() - BKQUOTE = auto() - _C1 = auto() - _C2 = auto() - _C3 = auto() - _C4 = auto() - _C5 = auto() - _C6 = auto() - _C7 = auto() - _C8 = auto() - _C9 = auto() - _CA = auto() - _CB = auto() - _CC = auto() - _CD = auto() - _CE = auto() - _CF = auto() - _D0 = auto() - _D1 = auto() - _D2 = auto() - _D3 = auto() - _D4 = auto() - _D5 = auto() - _D6 = auto() - _D7 = auto() - _D8 = auto() - _D9 = auto() - _DA = auto() - LBRKT = auto() - BKSLASH = auto() - RBRKT = auto() - QUOTE = auto() - oDF = auto() - oE0 = auto() - oE1 = auto() - oE2 = auto() - oE3 = auto() - oE4 = auto() - _E5 = auto() - oE6 = auto() - _E7 = auto() - _E8 = auto() - oE9 = auto() - oEA = auto() - oEB = auto() - oEC = auto() - oED = auto() - oEE = auto() - oEF = auto() - oF0 = auto() - oF1 = auto() - oF2 = auto() - oF3 = auto() - oF4 = auto() - oF5 = auto() - _F6 = auto() - _F7 = auto() - _F8 = auto() - _F9 = auto() - _FA = auto() - _FB = auto() - _FC = auto() - _FD = auto() - _FE = auto() - _FF = auto() diff --git a/core/python/keyman/keyboardprocessor/api.py b/core/python/keyman/keyboardprocessor/api.py deleted file mode 100644 index f7f642b9cf1..00000000000 --- a/core/python/keyman/keyboardprocessor/api.py +++ /dev/null @@ -1,119 +0,0 @@ -import pathlib -from typing import NamedTuple, NewType, Tuple, List, Union -from enum import Enum -from collections.abc import Sequence, Mapping - -USV = int -Marker = int -VirtualKey = int - - -class Context(Sequence): - Item = Union[USV, Marker] - - def __init__(initial: str): - pass - - def __del__(self): - pass - - def __str__(self): - pass - - def set(self, ctxt: List[Item]): - self.clear() - self.apped(ctxt) - - def clear(self): - pass - - def __getitem__(self, key: int) -> Item: - pass - - def __len__(self): - pass - - def append(self, ctxt: List[Item]): - pass - - def delete(self, remove_n: int, prefix: List[Item]): - pass - - -Option = Tuple[str, str] - - -class OptionSet(Mapping): - def __getitem__(self, key: str) -> Option: - pass - - def __iter__(self): - pass - - def __len__(self): - pass - - def __str__(self): - pass - - -class Keyboard(NamedTuple('__kb_attrs', version=str, id=str, folder_path=pathlib.Path, default_options=OptionSet)): - def __new__(cls, _): - return super(Keyboard, cls).__new__(cls, *[None]*4) - - def __init__(self, kb_path: pathlib.Path): - pass - - def __del__(self): - pass - - -class Action: - VKeyDown = NewType('Action.VirtualKey', VirtualKey) - # VKeyUp = VirtualKey - # VShiftDown = VirtualKey - # VShiftUp = VirtualKey - # Char = int - # Marker = int - # Bell = NewType('Bell', None) - # Back = NewType('Back', None) - # PersistOpt = str - # ResetOpt = str - - -ActionList = List[Action] - - -class State: - def __init__(self, kb: Keyboard, env: OptionSet): - pass - - def __del__(self): - pass - - @property - def flags(self) -> int: - pass - - @property - def context(self) -> Context: - pass - - @property - def environment(self) -> OptionSet: - pass - - @property - def options(self) -> OptionSet: - pass - - def indentify_option_src(opt: Option): - pass - - -def process_event(vk: VirtualKey, - modifier_state, - state: State, - acts: ActionList, - event_flags): - pass diff --git a/core/src/kmx/kmx_base.h b/core/src/kmx/kmx_base.h index ce3a1465cd4..562998472ca 100644 --- a/core/src/kmx/kmx_base.h +++ b/core/src/kmx/kmx_base.h @@ -10,41 +10,6 @@ #define strncasecmp _strnicmp #endif -#if defined(__LP64__) || defined(_LP64) -/* 64-bit, g++ */ -#define KMX_64BIT -#endif - -#if defined(_WIN64) && !defined(USE_64) -/* 64-bit, Windows */ -#define KMX_64BIT -#endif - -typedef uint32_t KMX_DWORD; -typedef int32_t KMX_BOOL; -typedef uint8_t KMX_BYTE; -typedef uint16_t KMX_WORD; - -typedef km_kbp_cp KMX_WCHAR; // wc, 16-bit UNICODE character -typedef KMX_WCHAR *PKMX_WCHAR; - -typedef char KMX_CHAR; -typedef KMX_CHAR *PKMX_CHAR; - -typedef uint32_t KMX_UINT; - -typedef KMX_BYTE *PKMX_BYTE; -typedef KMX_WORD *PKMX_WORD; -typedef KMX_DWORD *PKMX_DWORD; - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - namespace km { namespace kbp { namespace kmx { diff --git a/core/src/kmx/kmx_processevent.h b/core/src/kmx/kmx_processevent.h index d410b2fbb28..ef799bb9fd1 100644 --- a/core/src/kmx/kmx_processevent.h +++ b/core/src/kmx/kmx_processevent.h @@ -1,6 +1,13 @@ #pragma once +#ifndef KMN_KBP +#define KMN_KBP +#endif +#ifndef USE_CHAR16_T +#define USE_CHAR16_T +#endif + #include #include #include diff --git a/core/src/meson.build b/core/src/meson.build index 0ab24eb7f1a..0dc96d3926b 100644 --- a/core/src/meson.build +++ b/core/src/meson.build @@ -4,7 +4,7 @@ # Authors: Tim Eves (TSE) # -defns = ['-DKMN_KBP_EXPORTING'] +defns += ['-DKMN_KBP_EXPORTING'] version_res = [] if compiler.get_id() == 'gcc' or compiler.get_id() == 'clang' @@ -54,7 +54,7 @@ endif if compiler.get_id() == 'emscripten' warns = [] flags = [] - defns = [] + defns = ['-DKMN_KBP'] links = [] endif diff --git a/core/tests/unit/kmnkbd/meson.build b/core/tests/unit/kmnkbd/meson.build index 2a794ec1cbd..4cdaa91186e 100644 --- a/core/tests/unit/kmnkbd/meson.build +++ b/core/tests/unit/kmnkbd/meson.build @@ -13,7 +13,7 @@ else warns = [] endif -defns=['-DKMN_KBP_STATIC'] +defns+=['-DKMN_KBP_STATIC'] tests = [ ['context-api', 'context_api.cpp'], ['keyboard-api', 'keyboard_api.cpp'], diff --git a/core/tests/unit/kmnkbd/test_kmx_xstring.cpp b/core/tests/unit/kmnkbd/test_kmx_xstring.cpp index 3b944028c34..104851b7c59 100644 --- a/core/tests/unit/kmnkbd/test_kmx_xstring.cpp +++ b/core/tests/unit/kmnkbd/test_kmx_xstring.cpp @@ -4,6 +4,13 @@ * Keyman Core - KMX Extended String unit tests */ +#ifndef KMN_KBP +#define KMN_KBP +#endif +#ifndef USE_CHAR16_T +#define USE_CHAR16_T +#endif + #include #include #include @@ -11,7 +18,7 @@ #include #include #include "../../../src/kmx/kmx_xstring.h" -#include "../../../src/kmx/kmx_file.h" +#include #include "../test_assert.h" using namespace km::kbp::kmx; diff --git a/developer/src/tike/compile/CompileKeymanWeb.pas b/developer/src/tike/compile/CompileKeymanWeb.pas index f45651d22ba..af27c4f2fb7 100644 --- a/developer/src/tike/compile/CompileKeymanWeb.pas +++ b/developer/src/tike/compile/CompileKeymanWeb.pas @@ -1038,7 +1038,8 @@ function TCompileKeymanWeb.JavaScript_OutputString(FTabstops: string; fkp: PFILE begin if InQuotes then begin - Result := Result + '");'; + if not fgp.fReadOnly then + Result := Result + '");'; InQuotes := False; end; @@ -1223,9 +1224,9 @@ function TCompileKeymanWeb.JavaScript_OutputString(FTabstops: string; fkp: PFILE InQuotes := True; len := -1; end; - if rec.ChrVal in [Ord('"'), Ord('\')] then Result := Result + '\'; if not fgp.fReadOnly then begin + if rec.ChrVal in [Ord('"'), Ord('\')] then Result := Result + '\'; Result := Result + Javascript_String(rec.ChrVal); // I2242 end; end; @@ -1233,7 +1234,13 @@ function TCompileKeymanWeb.JavaScript_OutputString(FTabstops: string; fkp: PFILE pwsz := incxstr(pwsz); end; - if InQuotes then Result := Result + '");'; + if InQuotes then + begin + if not fgp.fReadOnly then + begin + Result := Result + '");'; + end; + end; end; function TCompileKeymanWeb.JavaScript_Shift(fkp: PFILE_KEY; FMnemonic: Boolean): Integer; @@ -2200,11 +2207,11 @@ function TCompileKeymanWeb.WriteCompiledKeyboard: string; {UTF8} { Write the groups out } // I853 - begin unicode missing causes crash -{ if fk.StartGroup[BEGIN_UNICODE] = $FFFFFFFF then + if fk.StartGroup[BEGIN_UNICODE] = $FFFFFFFF then begin - FCallback(fkp.Line, $4005, PChar('A "begin unicode" statement is required to compile a KeymanWeb keyboard')); + ReportError(0, CERR_InvalidBegin, 'A "begin unicode" statement is required to compile a KeymanWeb keyboard'); Exit; - end;} + end; Result := Result + WriteBeginStatement('gs', fk.StartGroup[BEGIN_UNICODE]); rec := ExpandSentinel(PChar(sBegin_NewContext)); diff --git a/developer/src/tike/project/Keyman.Developer.UI.Project.kmnProjectFileUI.pas b/developer/src/tike/project/Keyman.Developer.UI.Project.kmnProjectFileUI.pas index 57481848c20..9b2dd467c5b 100644 --- a/developer/src/tike/project/Keyman.Developer.UI.Project.kmnProjectFileUI.pas +++ b/developer/src/tike/project/Keyman.Developer.UI.Project.kmnProjectFileUI.pas @@ -67,6 +67,7 @@ implementation UfrmKeymanWizard, UfrmKeyboardFonts, UfrmMDIEditor, + UKeymanTargets, UmodWebHttpServer, Keyman.Developer.System.ServerAPI, Keyman.Developer.UI.ServerUI, @@ -133,7 +134,8 @@ function TkmnProjectFileUI.CompileKeyboard(FSilent: Boolean): Boolean; if Result and TServerDebugAPI.Running and - TServerDebugAPI.IsKeyboardRegistered(ProjectFile.TargetFileName) then + TServerDebugAPI.IsKeyboardRegistered(ProjectFile.TargetFileName) and + (ProjectFile.Targets * KMWKeymanTargets <> []) then TestKeymanWeb(True); end; @@ -235,7 +237,13 @@ function TkmnProjectFileUI.TestKeymanWeb(FSilent: Boolean): Boolean; // I4409 Exit(False); wizard := editor as TfrmKeymanWizard; + if ProjectFile.Targets * KMWKeymanTargets = [] then + Exit(False); + FCompiledName := ProjectFile.JSTargetFilename; + if FCompiledName = '' then + Exit(False); + if not TestKeyboardState(FCompiledName, FSilent) then Exit(False); diff --git a/docs/settings/linux/c_cpp_properties.json b/docs/settings/linux/c_cpp_properties.json index f6b6a18a49d..53f501fca75 100644 --- a/docs/settings/linux/c_cpp_properties.json +++ b/docs/settings/linux/c_cpp_properties.json @@ -2,7 +2,7 @@ "configurations": [ { "name": "linux", - "includePath": ["${workspaceFolder}/core/include/**"], + "includePath": ["${workspaceFolder}/common/include/","${workspaceFolder}/core/include/**"], "defines": [], "compilerPath": "/usr/lib/ccache/clang", "cStandard": "c11", diff --git a/docs/settings/linux/tasks.json b/docs/settings/linux/tasks.json index 51fe4d34eae..7beff2efe8e 100644 --- a/docs/settings/linux/tasks.json +++ b/docs/settings/linux/tasks.json @@ -66,7 +66,7 @@ "label": "ibus-keyman: configure", "command": "./configure", "args": [ - "CPPFLAGS=\"-DG_MESSAGES_DEBUG -I${workspaceFolder}/core/build/arch/debug/include/ -I${workspaceFolder}/core/include/\"", + "CPPFLAGS=\"-DG_MESSAGES_DEBUG -I${workspaceFolder}/core/build/arch/debug/include/ -I${workspaceFolder}/common/include/ -I${workspaceFolder}/core/include/\"", "CFLAGS=\"-g -O0\"", "CXXFLAGS=\"-g -O0\"", "KEYMAN_PROC_LIBS=\"-L${workspaceFolder}/common/core/desktop/build/arch/debug/src -lkmnkbp0\"", diff --git a/linux/debian/changelog b/linux/debian/changelog index b21640c5c7e..6990b7dbecc 100644 --- a/linux/debian/changelog +++ b/linux/debian/changelog @@ -1,3 +1,10 @@ +keyman (15.0.268-1) unstable; urgency=medium + + * New upstream release. + * Re-release to Debian + + -- Eberhard Beilharz Fri, 05 Aug 2022 17:31:36 +0200 + keyman (15.0.267-1) unstable; urgency=medium * New upstream release. diff --git a/linux/debian/rules b/linux/debian/rules index 87c36e453dc..5e2f0a86855 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -26,7 +26,7 @@ override_dh_auto_configure: # ibus-keyman cd linux/ibus-keyman && \ cp -f ../../VERSION.md VERSION && \ - export KEYMAN_PROC_CFLAGS="-I$(CURDIR)/core/build/arch/release/include -I$(CURDIR)/core/include" && \ + export KEYMAN_PROC_CFLAGS="-I$(CURDIR)/core/build/arch/release/include -I$(CURDIR)/common/include -I$(CURDIR)/core/include" && \ export KEYMAN_PROC_LIBS="-L$(CURDIR)/core/build/arch/release/src -lkmnkbp0" && \ export PKG_CONFIG_PATH=$(CURDIR)/core/build/arch/release/meson-private && \ ./autogen.sh && \ diff --git a/linux/ibus-keyman/README.md b/linux/ibus-keyman/README.md index 4f615d554fc..b22ccc3429f 100644 --- a/linux/ibus-keyman/README.md +++ b/linux/ibus-keyman/README.md @@ -24,6 +24,6 @@ For a debug build: To use the header files from the source repo, you need to specify paths to the include files in core: ```bash -./configure CPPFLAGS="-DG_MESSAGES_DEBUG -I../../core/build/arch/debug/include/ -I../../core/include/" \ +./configure CPPFLAGS="-DG_MESSAGES_DEBUG -I../../core/build/arch/debug/include/ -I../../common/include/ -I../../core/include/" \ CFLAGS="-g -O0" CXXFLAGS="-g -O0" ``` diff --git a/linux/ibus-keyman/tests/Makefile.am b/linux/ibus-keyman/tests/Makefile.am index 2a705520488..041acc0fa92 100644 --- a/linux/ibus-keyman/tests/Makefile.am +++ b/linux/ibus-keyman/tests/Makefile.am @@ -70,7 +70,7 @@ ibus_keyman_tests_SOURCES = \ ../../../core/src/kmx/kmx_environment.cpp \ ../../../core/src/kmx/kmx_environment.h \ ../../../core/src/kmx/kmx_file.cpp \ - ../../../core/src/kmx/kmx_file.h \ + ../../../common/include/kmx_file.h \ ../../../core/src/kmx/kmx_modifiers.cpp \ ../../../core/src/kmx/kmx_options.cpp \ ../../../core/src/kmx/kmx_options.h \ diff --git a/linux/keyman-config/keyman_config/install_kmp.py b/linux/keyman-config/keyman_config/install_kmp.py index 17c40e117bb..bed23e3f418 100755 --- a/linux/keyman-config/keyman_config/install_kmp.py +++ b/linux/keyman-config/keyman_config/install_kmp.py @@ -4,7 +4,7 @@ import logging import os import zipfile -from distutils.version import StrictVersion +from pkg_resources import parse_version from enum import Enum from shutil import rmtree @@ -127,7 +127,7 @@ def _install_kmp(self, inputfile, online, language, area): fileVersion = secure_lookup(system, 'fileVersion') if not fileVersion: fileVersion = '7.0' - if StrictVersion(fileVersion) > StrictVersion(__version__): + if parse_version(fileVersion) > parse_version(__version__): logging.error("install_kmp.py: error: %s requires a newer version of Keyman (%s)", inputfile, fileVersion) rmtree(self.packageDir) diff --git a/linux/keyman-config/keyman_config/install_window.py b/linux/keyman-config/keyman_config/install_window.py index d0ed6c70baa..faa64f103d9 100755 --- a/linux/keyman-config/keyman_config/install_window.py +++ b/linux/keyman-config/keyman_config/install_window.py @@ -15,7 +15,7 @@ gi.require_version('Gtk', '3.0') gi.require_version('WebKit2', '4.0') -from distutils.version import StrictVersion +from pkg_resources import parse_version from gi.repository import Gtk, WebKit2 @@ -107,8 +107,8 @@ def __init__(self, kmpfile, online=False, viewkmp=None, language=None): try: logging.info("package version %s", secure_lookup(info, 'version', 'description')) logging.info("installed kmp version %s", installed_kmp_ver) - if StrictVersion(secure_lookup(info, 'version', - 'description')) <= StrictVersion(installed_kmp_ver): + if parse_version(secure_lookup(info, 'version', + 'description')) <= parse_version(installed_kmp_ver): dialog = Gtk.MessageDialog( viewkmp, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, _("Keyboard is installed already")) diff --git a/linux/keyman-config/km-package-install b/linux/keyman-config/km-package-install index b1fbb36c809..ec4042faf3c 100755 --- a/linux/keyman-config/km-package-install +++ b/linux/keyman-config/km-package-install @@ -6,7 +6,7 @@ import logging import os import sys import time -from distutils.version import StrictVersion +from pkg_resources import parse_version from zipfile import is_zipfile from keyman_config import KeymanApiUrl, __version__, secure_lookup @@ -150,8 +150,8 @@ def main(): sys.exit(3) kbdata_v = secure_lookup(kbdata, 'version') if installed_kmp_v and kbdata_v: - kbdata_version = StrictVersion(kbdata_v) - installed_kmp_ver = StrictVersion(installed_kmp_v) + kbdata_version = parse_version(kbdata_v) + installed_kmp_ver = parse_version(installed_kmp_v) if kbdata_version == installed_kmp_ver: print("km-package-install: Version %s of the %s keyboard package is already installed." % (installed_kmp_ver, args.package)) diff --git a/linux/keyman-config/tests/test_uninstall_kmp.py b/linux/keyman-config/tests/test_uninstall_kmp.py index c8277d59605..a6e2aa301b1 100644 --- a/linux/keyman-config/tests/test_uninstall_kmp.py +++ b/linux/keyman-config/tests/test_uninstall_kmp.py @@ -25,40 +25,40 @@ def test_UninstallKeyboardsFromGnome_RemoveNonExistingKeyboard(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('ibus', 'fooDir/foo2.kmx')] + ('ibus', 'fooDir/foo2.kmx')] # Execute uninstall_keyboards_from_gnome([{'id': 'foo1'}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with([ - ('ibus', 'fooDir/foo2.kmx')]) + ('ibus', 'fooDir/foo2.kmx')]) def test_UninstallKeyboardsFromGnome_RemoveOneKeyboard(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'fooDir/foo1.kmx')] + ('xkb', 'en'), ('ibus', 'fooDir/foo1.kmx')] # Execute uninstall_keyboards_from_gnome([{'id': 'foo1'}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) def test_UninstallKeyboardsFromGnome_RemoveMultipleKeyboards(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'fooDir/foo1.kmx'), ('ibus', 'fooDir/foo2.kmx')] + ('xkb', 'en'), ('ibus', 'fooDir/foo1.kmx'), ('ibus', 'fooDir/foo2.kmx')] # Execute uninstall_keyboards_from_gnome([{'id': 'foo1'}, {'id': 'foo2'}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) def test_UninstallKeyboardsFromGnome_RemoveAllKeyboards(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('ibus', 'fooDir/foo1.kmx'), ('ibus', 'fooDir/foo2.kmx')] + ('ibus', 'fooDir/foo1.kmx'), ('ibus', 'fooDir/foo2.kmx')] # Execute uninstall_keyboards_from_gnome([{'id': 'foo1'}, {'id': 'foo2'}], 'fooDir') # Verify @@ -68,45 +68,45 @@ def test_UninstallKeyboardsFromGnome_RemoveKeyboard_SingleLanguage(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx')] + ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx')] # Execute uninstall_keyboards_from_gnome([{'id': 'foo1', 'languages': [{'id': 'en'}]}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) def test_UninstallKeyboardsFromGnome_RemoveKeyboard_MultipleLanguages(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'fr:fooDir/foo1.kmx')] + ('xkb', 'en'), ('ibus', 'fr:fooDir/foo1.kmx')] # Execute uninstall_keyboards_from_gnome( - [{'id': 'foo1', 'languages': [{'id': 'en'}, {'id': 'fr'}]}], 'fooDir') + [{'id': 'foo1', 'languages': [{'id': 'en'}, {'id': 'fr'}]}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) def test_UninstallKeyboardsFromGnome_RemoveKeyboard_OneNotMatchingLanguage(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx')] + ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx')] # Execute uninstall_keyboards_from_gnome( - [{'id': 'foo1', 'languages': [{'id': 'fr'}]}], 'fooDir') + [{'id': 'foo1', 'languages': [{'id': 'fr'}]}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) def test_UninstallKeyboardsFromGnome_RemoveKeyboard_RemovesAllMatching(self): # Setup mockGnomeKeyboardsUtilInstance = self.mockGnomeKeyboardsUtilClass.return_value mockGnomeKeyboardsUtilInstance.read_input_sources.return_value = [ - ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx'), ('ibus', 'fr:fooDir/foo1.kmx')] + ('xkb', 'en'), ('ibus', 'en:fooDir/foo1.kmx'), ('ibus', 'fr:fooDir/foo1.kmx')] # Execute uninstall_keyboards_from_gnome( - [{'id': 'foo1', 'languages': [{'id': 'fr'}]}], 'fooDir') + [{'id': 'foo1', 'languages': [{'id': 'fr'}]}], 'fooDir') # Verify mockGnomeKeyboardsUtilInstance.write_input_sources.assert_called_once_with( - [('xkb', 'en')]) + [('xkb', 'en')]) diff --git a/linux/scripts/build.sh b/linux/scripts/build.sh index a5f090848cb..9a6b960f4bf 100755 --- a/linux/scripts/build.sh +++ b/linux/scripts/build.sh @@ -60,12 +60,12 @@ function buildproject() { if [[ "${BUILDONLY}" == "no" ]]; then echo "Configuring $proj" if [[ "${INSTALLDIR}" == "/tmp/kmfl" ]]; then # don't install ibus-kmfl or ibus-keyman into ibus - ../${subdir}$proj/configure KEYMAN_PROC_CFLAGS="-I\$(top_builddir)/../keyboardprocessor/arch/release/include -I\$(top_builddir)/../../core/include" \ + ../${subdir}$proj/configure KEYMAN_PROC_CFLAGS="-I\$(top_builddir)/../keyboardprocessor/arch/release/include -I\$(top_builddir)/../../common/include -I\$(top_builddir)/../../core/include" \ CPPFLAGS="-I\$(top_builddir)/../build-kmflcomp -I\$(top_builddir)/../build-libkmfl" \ KEYMAN_PROC_LIBS="-L`pwd`/../build-libkmfl/src -L`pwd`/../keyboardprocessor/arch/release/src -lkmnkbp0" \ LDFLAGS="-L`pwd`/../build-kmflcomp/src -L`pwd`/../build-libkmfl/src" --prefix=${INSTALLDIR} --libexecdir=${INSTALLDIR}/lib/ibus else # install ibus-kmfl and ibus-keyman into ibus - ../${subdir}$proj/configure KEYMAN_PROC_CFLAGS="-I\$(top_builddir)/../keyboardprocessor/arch/release/include -I\$(top_builddir)/../../core/include" \ + ../${subdir}$proj/configure KEYMAN_PROC_CFLAGS="-I\$(top_builddir)/../keyboardprocessor/arch/release/include -I\$(top_builddir)/../../common/include -I\$(top_builddir)/../../core/include" \ CPPFLAGS="-I\$(top_builddir)/../build-kmflcomp -I\$(top_builddir)/../build-libkmfl" \ LDFLAGS="-L`pwd`/../build-kmflcomp/src -L`pwd`/../build-libkmfl/src" \ KEYMAN_PROC_LIBS="-L`pwd`/../build-libkmfl/src -L`pwd`/../keyboardprocessor/arch/release/src -lkmnkbp0" \ diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh index e0d876a5081..7bc54e37225 100755 --- a/linux/scripts/dist.sh +++ b/linux/scripts/dist.sh @@ -68,16 +68,17 @@ for proj in ${extra_projects}; do dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \ --tar-ignore=.gitignore --tar-ignore=experiments --tar-ignore=debian \ --tar-ignore=.github --tar-ignore=.vscode --tar-ignore=android \ - --tar-ignore=common/lexical-model-types \ --tar-ignore=common/models --tar-ignore=common/predictive-text \ - --tar-ignore=common/test --tar-ignore=developer --tar-ignore=docs --tar-ignore=ios \ + --tar-ignore=common/resources --tar-ignore=common/schemas \ + --tar-ignore=common/test --tar-ignore=common/web --tar-ignore=common/windows \ + --tar-ignore=developer --tar-ignore=docs --tar-ignore=ios \ --tar-ignore=linux/keyman-config/buildtools/build-langtags.py --tar-ignore=__pycache__ \ --tar-ignore=linux/help --tar-ignore=linux/Jenkinsfile \ --tar-ignore=linux/keyboardprocessor --tar-ignore=linux/legacy \ --tar-ignore=mac --tar-ignore=node_modules --tar-ignore=oem \ --tar-ignore=linux/build* --tar-ignore=core/build \ --tar-ignore=resources/devbox --tar-ignore=resources/git-hooks \ - --tar-ignore=resources/scopes --tar-ignore=common/web \ + --tar-ignore=resources/scopes \ --tar-ignore=resources/build/*.lua --tar-ignore=resources/build/jq* \ --tar-ignore=resources/build/vswhere* --tar-ignore=results \ --tar-ignore=web --tar-ignore=windows --tar-ignore=keyman_1* \ diff --git a/linux/scripts/jenkins.sh b/linux/scripts/jenkins.sh index 4fe776c40f7..c7406d88314 100755 --- a/linux/scripts/jenkins.sh +++ b/linux/scripts/jenkins.sh @@ -1,16 +1,19 @@ -#!/bin/bash -e +#!/bin/bash # $1 - project name with appended tier, e.g. ibus-kmfl-alpha # $2 - GPG key used for signing the source package -PROGRAM_NAME="$(basename "$0")" +set -e +set -u -. $HOME/ci-builder-scripts/bash/common.sh -init --no-package +## 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 + +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" keyman_projects="keyman" -if [ -n "$BUILD_LEGACY" ]; then - keyman_projects="keyman kmflcomp libkmfl ibus-kmfl" -fi tier="stable" @@ -24,72 +27,59 @@ proj="$1" proj=${proj%"-alpha"} proj=${proj%"-beta"} -if [ "$proj" == "keyman" ]; then - fullsourcename="keyman" - sourcedir="$KEYMAN_ROOT" -else - # check if project is known - if [[ $keyman_projects =~ (^|[[:space:]])$proj($|[[:space:]]) ]]; then - fullsourcename="$1" - sourcedir="legacy/$proj" - else - stderr "$proj not in known projects ($keyman_projects)" - exit -1 - fi -fi +fullsourcename="keyman" +sourcedir="$KEYMAN_ROOT" sourcename=${fullsourcename%"-alpha"} sourcename=${sourcename%"-beta"} +# set Debian/changelog environment +export DEBFULLNAME="${fullsourcename} Package Signing Key" +export DEBEMAIL='jenkins@sil.org' + checkAndInstallRequirements() { - local TOINSTALL + local TOINSTALL="" - for p in dh-python gir1.2-webkit2-4.0 python3-all python3-setuptools \ - python3-requests python3-requests-cache python3-numpy python3-pil python3-lxml \ - python3-gi python3-magic python3-qrcode cargo build-essential python3-dbus + for p in devscripts equivs do - if ! dpkg -l | grep -q $p; then + if ! dpkg -s $p >/dev/null 2>&1; then TOINSTALL="$TOINSTALL $p" fi done - if [ ! -f /usr/bin/perl ]; then - TOINSTALL="$TOINSTALL perl" - fi - - if [ ! -f /usr/bin/meson ]; then - TOINSTALL="$TOINSTALL meson" - fi + export DEBIAN_FRONTEND=noninteractive if [ -n "$TOINSTALL" ]; then - log "Installing prerequisites:$TOINSTALL" sudo apt-get update sudo apt-get -qy install $TOINSTALL fi + + sudo mk-build-deps debian/control + sudo apt-get -qy install ./keyman-build-deps_*.deb + sudo rm -f keyman-buid-deps_* } checkAndInstallRequirements # clean up prev deb builds -log "cleaning previous builds of $1" - +echo_heading "cleaning previous builds of $1" rm -rf builddebs rm -rf $sourcedir/${1}_*.{dsc,build,buildinfo,changes,tar.?z,log} rm -rf $sourcedir/../${1}_*.{dsc,build,buildinfo,changes,tar.?z,log} -log "Make source package for $fullsourcename" -log "reconfigure" +echo_heading "Make source package for $fullsourcename" +echo_heading "reconfigure" JENKINS="yes" TIER="$tier" ./scripts/reconf.sh $sourcename -log "Make origdist" +echo_heading "Make origdist" ./scripts/dist.sh origdist $sourcename -log "Make deb source" +echo_heading "Make deb source" ./scripts/deb.sh sourcepackage $proj #sign source package -for file in `ls builddebs/*.dsc`; do - log "Signing source package $file" +for file in $(ls builddebs/*.dsc); do + echo_heading "Signing source package $file" debsign -k$2 $file done diff --git a/package-lock.json b/package-lock.json index ad25cc7212c..03dd8ee2b05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -577,8 +577,8 @@ "typescript": "^4.5.4" }, "optionalDependencies": { - "hetrodo-node-hide-console-window-napi": "keymanapp/hetrodo-node-hide-console-window-napi#keyman-15.0", - "node-windows-trayicon": "keymanapp/node-windows-trayicon#keyman-15.0" + "hetrodo-node-hide-console-window-napi": "git+ssh://git@github.com/keymanapp/hetrodo-node-hide-console-window-napi.git#858b23036a9963b40ad6ff3c5bacd421e5839b92", + "node-windows-trayicon": "git+ssh://git@github.com/keymanapp/node-windows-trayicon.git#1e46786082213f3edcddd5953e33f5abdc7ea05f" } }, "developer/src/server/node_modules/@cspotcode/source-map-support": { @@ -865,11 +865,12 @@ "dev": true }, "node_modules/@actions/core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", - "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", + "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "dependencies": { - "@actions/http-client": "^2.0.1" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" } }, "node_modules/@actions/github": { @@ -6867,7 +6868,7 @@ "name": "@keymanapp/auto-history-action", "license": "MIT", "dependencies": { - "@actions/core": "^1.2.6", + "@actions/core": "^1.9.1", "@actions/github": "^2.1.0", "typescript": "^4.5.4", "yargs": "^15.1.0" @@ -7122,11 +7123,12 @@ }, "dependencies": { "@actions/core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", - "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", + "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "requires": { - "@actions/http-client": "^2.0.1" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" } }, "@actions/github": { @@ -7188,7 +7190,7 @@ "@keymanapp/auto-history-action": { "version": "file:resources/build/version", "requires": { - "@actions/core": "^1.2.6", + "@actions/core": "^1.9.1", "@actions/github": "^2.1.0", "@types/node": "^13.7.0", "@types/semver": "^7.1.0", @@ -7355,11 +7357,11 @@ "chalk": "^4.1.2", "copyfiles": "^2.4.1", "express": "^4.17.2", - "hetrodo-node-hide-console-window-napi": "keymanapp/hetrodo-node-hide-console-window-napi#keyman-15.0", + "hetrodo-node-hide-console-window-napi": "git+ssh://git@github.com/keymanapp/hetrodo-node-hide-console-window-napi.git#858b23036a9963b40ad6ff3c5bacd421e5839b92", "mocha": "^9.1.4", "multer": "^1.4.4", "ngrok": "^4.2.2", - "node-windows-trayicon": "keymanapp/node-windows-trayicon#keyman-15.0", + "node-windows-trayicon": "git+ssh://git@github.com/keymanapp/node-windows-trayicon.git#1e46786082213f3edcddd5953e33f5abdc7ea05f", "open": "^8.4.0", "ts-node": "^10.4.0", "tsc-watch": "^4.5.0", diff --git a/resources/build/version/package.json b/resources/build/version/package.json index 1a4e8355c87..33698434fb7 100644 --- a/resources/build/version/package.json +++ b/resources/build/version/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "@actions/core": "^1.2.6", + "@actions/core": "^1.9.1", "@actions/github": "^2.1.0", "typescript": "^4.5.4", "yargs": "^15.1.0" diff --git a/web/source/kmwuibutton.ts b/web/source/kmwuibutton.ts index 23958dcc3a0..1205c7b6e40 100644 --- a/web/source/kmwuibutton.ts +++ b/web/source/kmwuibutton.ts @@ -6,7 +6,7 @@ // If a UI module has been loaded, we can rely on the publically-published 'name' property // having been set as a way to short-out a UI reload. Its parent object always exists by // this point in the build process. -if(!window['keyman']['ui']['name']) { +if(!window['keyman']['ui']['name']) { /********************************/ /* */ @@ -21,126 +21,127 @@ if(!window['keyman']['ui']['name']) { * Instead, use the --output-wrapper command during optimization, which will * add the anonymous function to enclose all code, including those optimized * variables which would otherwise have global scope. - **/ + **/ try { // Declare KeymanWeb, OnScreen keyboard and Util objects var keymanweb=window['keyman'], util=keymanweb['util'],dbg=keymanweb['debug']; - + // Disable UI for touch devices if(util['isTouchDevice']()) throw ''; - - // User interface global and variables + + // User interface global and variables keymanweb['ui'] = {}; var ui=keymanweb['ui']; ui['name'] = 'button'; - - ui.init = false; + + ui.init = false; + ui.initTimer = null; ui.KeyboardSelector = null; ui.KeymanWeb_DefaultKeyboardHelp='KeymanWeb is not running. Choose a keyboard from the list'; - ui._KeymanWeb_KbdList = null; - ui._KMWSel = null; - ui._IsHelpVisible = false; + ui._KeymanWeb_KbdList = null; + ui._KMWSel = null; + ui._IsHelpVisible = false; ui._DefaultKeyboardID = ''; ui.updateTimer = null; ui.updateList = true; - + /** * Highlight the currently active keyboard in the list of keyboards - **/ + **/ ui._ShowSelected = function() { - var _rv,kbd=keymanweb['getActiveKeyboard'](),lgc=keymanweb['getActiveLanguage'](), + var _rv,kbd=keymanweb['getActiveKeyboard'](),lgc=keymanweb['getActiveLanguage'](), kList = ui._KeymanWeb_KbdList.childNodes, _r = /^KMWSel_(.*)\$(.*)$/; - + for(var i=1; i= kList.length) i=1; - kList[i].childNodes[0].className = 'selected'; - } - + } + if(i >= kList.length) i=1; + kList[i].childNodes[0].className = 'selected'; + } + /** * Select keyboard by id - * + * * @param {Event} _id keyboard selection event - * @return {boolean} + * @return {boolean} */ ui._SelectKeyboard = function(_id) - { - if(typeof(_id) == 'object') + { + if(typeof(_id) == 'object') { var t=null; if((typeof(_id.target) != 'undefined') && _id.target) t=_id.target; - else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) t=_id.srcElement; + else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) t=_id.srcElement; if(t) _id=t.id; } - - var _r=/^KMWSel_(.*)\$(.*)$/; + + var _r=/^KMWSel_(.*)\$(.*)$/; var _rv=_r.exec(_id),_lgc='',_name=''; - if(_rv !== null) + if(_rv !== null) { _name = _rv[1].split('$')[0]; //new code - _lgc = _id.split('$')[1]; + _lgc = _id.split('$')[1]; if(ui._KMWSel != null) ui._KMWSel.className = ''; - var _k = document.getElementById(_id); - if(_k) _k.className='selected'; - ui._KMWSel = _k; + var _k = document.getElementById(_id); + if(_k) _k.className='selected'; + ui._KMWSel = _k; keymanweb['setActiveKeyboard'](_name,_lgc); } - else + else _name=null; - + keymanweb['focusLastActiveElement'](); let osk = keymanweb.osk; - if(osk && osk['isEnabled']()) osk['show'](true); + if(osk && osk['isEnabled']()) osk['show'](true); ui._ShowKeyboardButton(_name); return false; - } + } /** * Set KMW UI activation state on mouse click - * + * * @param {Event} e event - */ + */ ui._SelectorMouseDown = function(e) - { - var x=keymanweb['getLastActiveElement'](); + { + var x=keymanweb['getLastActiveElement'](); // Set the focus to an input field, to get correct OSK display behaviour if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); - + if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); } /** * Set focus on mouse up - * + * * @param {Event} e event - */ + */ ui._SelectorMouseUp = function(e) - { + { var x=keymanweb['getLastActiveElement'](); - + // Set the focus to an input field, to get correct OSK display behaviour if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); } /** * Set KMW UI activation state on mouse over - * + * * @param {Event} e event - */ + */ ui._SelectorMouseOver = function(e) { // highlight the currently active keyboard @@ -155,21 +156,21 @@ if(!window['keyman']['ui']['name']) { /** * Sets the focus to the first input or textarea found on the current page - * to ensure consistent keyboard selection and OSK display behaviour - */ + * to ensure consistent keyboard selection and OSK display behaviour + */ ui._FocusFirstInput = function() { var i,ip=null,tp=null, iList=document.getElementsByTagName("input"), tList=document.getElementsByTagName("textarea"); - + for(i=0; i 0) tp = tList[0]; - + if((!ip) && (!tp)) return; else if(ip && !tp) @@ -185,12 +186,12 @@ if(!window['keyman']['ui']['name']) { else tp.focus(); } - + /** * Clear KMW UI activation state on mouse out - * + * * @param {Event} e event - */ + */ ui._SelectorMouseOut = function(e) { if(keymanweb['activatingUI']) keymanweb['activatingUI'](0); @@ -199,9 +200,9 @@ if(!window['keyman']['ui']['name']) { /** * Disable the button to show/hide the OSK if no active keyboard or active keyboard is CJK (user cannot hide) - * + * * @param {?string=} _name current keyboard name - */ + */ ui._ShowKeyboardButton = function(_name) { var kbdName = keymanweb['getActiveKeyboard'](), kbdId=document.getElementById("KMW_Keyboard"); @@ -209,17 +210,17 @@ if(!window['keyman']['ui']['name']) { if(kbdId) { if((kbdName == '') || keymanweb['isCJK']()) - { + { kbdId.className='kmw_disabled'; - } + } else { let osk = keymanweb.osk; kbdId.className = osk && osk['isEnabled']() ? 'kmw_show' : 'kmw_hide'; } } - } - + } + ui.registerEvents = function() { let osk = keymanweb.osk; if(!osk) { @@ -227,72 +228,79 @@ if(!window['keyman']['ui']['name']) { } /** * UI Functions called by KeymanWeb or OSK - */ - osk['addEventListener']('show', function(oskPosition) { + */ + osk['addEventListener']('show', function(oskPosition) { var t=keymanweb['getLastActiveElement'](); if(t) - { + { if(!oskPosition['userLocated']) { oskPosition['x'] = util['getAbsoluteX'](t); oskPosition['y'] = util['getAbsoluteY'](t)+t.offsetHeight; } - } - + } + ui._ShowKeyboardButton(); - return oskPosition; - }); + return oskPosition; + }); - /* TODO: why is this still needed??? Does it actually do anything?? */ - osk['addEventListener']('hide', function(hiddenByUser) { + /* TODO: why is this still needed??? Does it actually do anything?? */ + osk['addEventListener']('hide', function(hiddenByUser) { if((arguments.length > 0) && hiddenByUser) { var _a = document.getElementById('KMW_Keyboard'); if(_a) _a.className = 'kmw_hide'; - } - }); + } + }); } - + /** * Show or hide the OSK (always visible for CJK keyboards) - * + * * @param {Object} _anchor anchor element (?) - * @return {boolean} - **/ - ui._ShowKeymanWebKeyboard = function(_anchor) - { + * @return {boolean} + **/ + ui._ShowKeymanWebKeyboard = function(_anchor) + { var kbdId=document.getElementById("KMW_Keyboard"); let osk = keymanweb.osk; - if((kbdId.className!='kmw_disabled') && osk && osk['show']) + if((kbdId.className!='kmw_disabled') && osk && osk['show']) { if(osk['isEnabled']()) osk['hide'](); else osk['show'](true); } if(window.event) window.event.returnValue=false; - keymanweb['focusLastActiveElement'](); - return false; + keymanweb['focusLastActiveElement'](); + return false; } /** * Initialize Button User Interface - **/ + **/ ui['initialize'] = ui.Initialize = function() { + if(ui.initTimer) { + window.clearTimeout(ui.initTimer); + ui.initTimer = null; + } + //Never initialize UI before KMW (parameters will be undefined) - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,250); return; + if(!keymanweb['initialized']) { + ui.initTimer = window.setTimeout(ui.Initialize, 50); + return; + } + + if(ui.init || util['isTouchDevice']()) { + return; } - - if(ui.init || util['isTouchDevice']()) return; - + ui.init = true; - + util['addStyleSheet'](ui._Appearance); - + ui._KeymanWeb_KbdList = util['createElement']('ul'); ui._KeymanWeb_KbdList.id = 'KeymanWeb_KbdList'; - + var _elem = document.getElementById('KeymanWebControl'); if(!_elem) { @@ -305,25 +313,25 @@ if(!window['keyman']['ui']['name']) { } } } - + // Insert as first child of body if not defined by user if(!_elem && (document.body != null)) { _elem=document.createElement('DIV'); - _elem.id='KeymanWebControl'; + _elem.id='KeymanWebControl'; document.body.insertBefore(_elem,document.body.firstChild); ui._insertedElem = _elem; } - - + + var imgPath=util['getOption']('resources')+'ui/button/'; if(_elem) - { + { // Append another DIV to follow the main control with clear:both to prevent selection over entire width of window var dx=document.createElement('DIV'),ds=dx.style; ds.clear='both'; _elem.parentNode.insertBefore(dx,_elem.nextSibling); - + var _btn=util['createElement']('img'), _ul=util['createElement']('ul'),_li0=util['createElement']('li'); _btn.id = 'kmwico_a'; _btn.src = imgPath+'kmw_button.gif'; @@ -339,20 +347,20 @@ if(!window['keyman']['ui']['name']) { else return; if(!keymanweb['iOS']) - { - var _li = util['createElement']('li'); + { + var _li = util['createElement']('li'); var _a = util['createElement']('a'); var _img = util['createElement']('img'); _img.src = imgPath+'kbdicon.gif'; _a.appendChild(_img); - - var _txt1 = document.createTextNode(' Hide Keyboard'); + + var _txt1 = document.createTextNode(' Hide Keyboard'); var _txt2 = document.createTextNode(' Show Keyboard'); var _sp1 = util['createElement']('span'); _sp1.id = 'KMW_KbdVisibleMsg'; _sp1.appendChild(_txt1); _a.appendChild(_sp1); - + var _sp2 = util['createElement']('span'); _sp2.id = 'KMW_KbdHiddenMsg'; _sp2.appendChild(_txt2); @@ -366,29 +374,29 @@ if(!window['keyman']['ui']['name']) { ui._KeymanWeb_KbdList.appendChild(_li); } - var _li1 = util['createElement']('li'); - _li1.id = 'KMW_ButtonUI_KbdList'; + var _li1 = util['createElement']('li'); + _li1.id = 'KMW_ButtonUI_KbdList'; var _a1 = util['createElement']('a'); _a1.appendChild(document.createTextNode('(System keyboard)')); _a1.onclick = ui._SelectKeyboard; - _a1.href = '#'; + _a1.href = '#'; _a1.id='KMWSel_$'; _a1.className='selected'; _li1.appendChild(_a1); ui._KMWSel = _a1; ui._KeymanWeb_KbdList.appendChild(_li1); - var _kbds = keymanweb['getKeyboards'](), _added = []; + var _kbds = keymanweb['getKeyboards'](), _added = []; ui.updateKeyboardList(); - + document.getElementById('kmwico_li').appendChild(ui._KeymanWeb_KbdList); var _sfEl = document.getElementById("kmwico_li"); util['attachDOMEvent'](_sfEl,'mousedown',ui._SelectorMouseDown); util['attachDOMEvent'](_sfEl,'mouseover',ui._SelectorMouseOver); - util['attachDOMEvent'](_sfEl,'mouseout',ui._SelectorMouseOut); + util['attachDOMEvent'](_sfEl,'mouseout',ui._SelectorMouseOut); util['attachDOMEvent'](_sfEl,'mouseup',ui._SelectorMouseUp); ui.registerEvents(); @@ -404,108 +412,108 @@ if(!window['keyman']['ui']['name']) { /** * Keyboard registration event handler - * - * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, + * + * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, * thus updating only once when only if multiple keyboards are registered together - */ - keymanweb['addEventListener']('keyboardregistered', + */ + keymanweb['addEventListener']('keyboardregistered', function(p) - { + { ui.updateList = true; if(ui.updateTimer) clearTimeout(ui.updateTimer); ui.updateTimer = setTimeout(ui.updateKeyboardList,20); - }); + }); /** * Update the entire menu when keyboards are registered or deregistered - **/ + **/ ui.updateKeyboardList = function() - { + { ui.updateList = false; - + if(!ui.init) return; - + // Clear existing list first (first two nodes must be preserved) for(var i:number=ui._KeymanWeb_KbdList.childNodes.length; i>2; i--) ui._KeymanWeb_KbdList.removeChild(ui._KeymanWeb_KbdList.childNodes[i-1]); - + var kbds=keymanweb['getKeyboards'](); if(kbds.length > 0) { for(var i:number=0; i 26) _t=_t.substr(0,24)+'\u2026'; - _a2.appendChild(document.createTextNode(_t)); + _a2.appendChild(document.createTextNode(_t)); _a2.onclick = ui._SelectKeyboard; _a2.href = '#'; _a2.id='KMWSel_'+Lki+'$'+Lklc; _li2.appendChild(_a2); ui._KeymanWeb_KbdList.appendChild(_li2); } - + // Define appearance of this interface - ui._Appearance = + ui._Appearance = "#kmwico, #kmwkbd {"+ "vertical-align: middle;"+ "} "+ "#KeymanWebControl {float:left;} "+ - + "#KeymanWebControl * "+ "{"+ "letter-spacing: 0px !important;"+ "line-height: 1li !important;"+ "white-space: nowrap !important;"+ "} "+ - + "#KeymanWebControl #kmwico img {"+ "vertical-align: top;"+ "padding: 0;"+ "margin: 0;"+ "border: none;"+ "} "+ - + "#KeymanWebControl #kmwico, #kmwico ul {"+ "padding: 0;"+ "margin: 0;"+ "list-style: none;"+ "} "+ - + "#KeymanWebControl #kmwico_a {"+ "display: block;"+ //"border: none !important;"+ "width: 22px; height: 23px; "+ /* sizes needed for kmw_button.gif */ "} "+ - + "#KeymanWebControl #kmwico li { "+ "text-align: left;"+ "} "+ - + "#KeymanWebControl #kmwico li ul {"+ "display: block;"+ "position: absolute;"+ @@ -516,27 +524,27 @@ if(!window['keyman']['ui']['name']) { "box-shadow: 4px 4px 2px #666;"+ "z-index: 10011;"+ /* above the osk */ "} "+ - + "#KeymanWebControl #kmwico li.sfunhover ul {"+ "display: none; left: -5999px;"+ "} "+ - + "#KeymanWebControl #kmwico li:hover ul, #kmwico li.sfhover ul {"+ "display: block;"+ "left: auto;"+ "} "+ - + "#KeymanWebControl #kmwico ul li {"+ "float: none;"+ "padding: 0 !important;"+ "margin: 0 !important;"+ "width: 136px !important;"+ "} "+ - + "#KeymanWebControl #KMW_LanguageName {"+ "font-weight: bold;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a, #kmwico ul li a:visited {"+ "display: block;"+ "padding: 2px 4px !important;"+ @@ -547,17 +555,17 @@ if(!window['keyman']['ui']['name']) { "font-size: 8pt;"+ "text-decoration: none;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a.selected {"+ "font-weight: bold;"+ "color: black;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a:hover {"+ "color: white;"+ "background-color: #ad4a28;"+ "} "+ - + "#KeymanWebControl #kmwico ul li a.kmw_disabled, #KeymanWebControl #kmwico ul li a.kmw_disabled:hover {"+ "color: #c0c0c0; cursor: default;"+ "background-color: white;"+ @@ -581,13 +589,9 @@ if(!window['keyman']['ui']['name']) { "#KeymanWebControl #kmwico ul li#KMW_ButtonUI_KbdIcon {"+ "border-bottom: solid 1px #ad4a28;"+ - "} "; + "} "; - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading ui.Initialize(); - } catch(err){} } \ No newline at end of file diff --git a/web/source/kmwuifloat.ts b/web/source/kmwuifloat.ts index 2367fbe61be..b9313f6e2f9 100644 --- a/web/source/kmwuifloat.ts +++ b/web/source/kmwuifloat.ts @@ -48,6 +48,7 @@ if(!window['keyman']['ui']['name']) { ui.updateTimer = null; // prevent unnecessary list refreshing ui.floatRight = false; // align left by default ui.initialized = false; // initialization flag + ui.initTimer = null; /** * Display or hide the OSK from the OSK icon link @@ -71,15 +72,21 @@ if(!window['keyman']['ui']['name']) { * Scope Private * Description UI Initialization **/ - ui['initialize'] = ui.Initialize = function() - { + ui['initialize'] = ui.Initialize = function() { + if(ui.initTimer) { + window.clearTimeout(ui.initTimer); + ui.initTimer = null; + } + // Must always initialize after keymanWeb itself, otherwise options are undefined - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,50); return; + if(!keymanweb['initialized']) { + ui.initTimer = window.setTimeout(ui.Initialize, 50); + return; } - if(ui.initialized || util['isTouchDevice']()) return; + if(ui.initialized || util['isTouchDevice']()) { + return; + } var imgPath=util['getOption']('resources')+"ui/float/"; @@ -541,9 +548,6 @@ if(!window['keyman']['ui']['name']) { if(window.addEventListener) window.addEventListener('resize', ui._Resize, false); - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading ui.Initialize(); diff --git a/web/source/kmwuitoolbar.ts b/web/source/kmwuitoolbar.ts index 8d603cd5f15..0bfc00d0299 100644 --- a/web/source/kmwuitoolbar.ts +++ b/web/source/kmwuitoolbar.ts @@ -1215,9 +1215,8 @@ if(!window['keyman']['ui']['name']) { } // Initialize when everything defined (replaces unreliable onload event handler) - // ui.initToolbarUI(); - // No, initialization must not be done before KMW is ready! - // ui.initialize() is now called by keymanweb when document is ready and kmw initialization completed - + // In case the toolbar script loads a bit later than the main KMW script + // (may happen in unit testing) + ui.initToolbarUI(); // equivalent to ui.Initialize() from the other UI modules } catch(ex){} } \ No newline at end of file diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index cb9208cd6fe..a488b1bc3ba 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -55,11 +55,11 @@ $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\core\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 9043c9ece16..23240b2a067 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -258,15 +258,12 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->TIPGetContext = ctfunc; AppContextWithStores *savedContext = NULL; // I4370 // I4978 - AppContext *savedContextUsingCore = NULL; // used for common core - km_kbp_option_item *SavedKBDOptions = NULL; // used for common core + if (!Updateable) { - if (isUsingCoreProcessor) { - savedContextUsingCore = new AppContext(); - _td->app->CopyContext(savedContextUsingCore); - SavedKBDOptions = SaveKeyboardOptionsCore(_td->lpActiveKeyboard); - } else { // I4370 - savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4978 + // The core processor km_kbp_process_event is only called once per key stroke + // therefore there is no need to preserve context and keyboard actions + if (!isUsingCoreProcessor) { + savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4370 // I4978 _td->app->SaveContext(savedContext); } } @@ -274,17 +271,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM BOOL res = ProcessHook(); if (!Updateable) { - if (isUsingCoreProcessor) { - if (res) { - // Reset the context if match found - _td->app->RestoreContextOnly(savedContextUsingCore); - RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, SavedKBDOptions); - DisposeKeyboardOptionsCore(&SavedKBDOptions); - delete savedContextUsingCore; - savedContextUsingCore = NULL; - } - } else { // I4370 - if (res) { // I4585 + if (!isUsingCoreProcessor) { + if (res) { // I4585 // I4370 // Reset the context if match found _td->app->RestoreContext(savedContext); delete savedContext; diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index 5f27accaccb..49725bc50a7 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -55,11 +55,11 @@ $(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\core\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\core\include;$(IncludePath) $(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\core\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\core\include;$(IncludePath)