chore(web): Merge branch 'refactor/web/keytip-abstraction' into refactor/web/subkey-popup-encapsulation

This commit is contained in:
jahorton 2021-06-16 08:22:47 +07:00
commit 3de1686cd0
37 changed files with 177 additions and 183 deletions

View file

@ -1,5 +1,15 @@
# Keyman Version History
## 15.0.68 alpha 2021-06-15
* chore(common): Add YouTube links to Keyman 14 features (#5276)
* chore(common): Check in crowdin strings for Spanish (Latin America) (#5269)
* refactor(web): polishes management of OSK keys (#5257)
* refactor(web): Visual Keyboard disentanglement - pass 1 (#5259)
* refactor(web): VisualKeyboard height styling consistency (#5278)
* fix(common/models): predictive-text engine use of NFD input (#5273)
* chore(linux): Fix warnings (#5282)
## 15.0.67 alpha 2021-06-12
* feat(linux): Fix Linux packaging on i386 (#5250)

View file

@ -1 +1 @@
15.0.68
15.0.69

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/input-processor",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/input-processor",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/resources-gosh": "^15.0.68",
"@keymanapp/lexical-model-compiler": "^15.0.69",
"@keymanapp/resources-gosh": "^15.0.69",
"@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.68",
"@keymanapp/lexical-model-layer": "^15.0.68",
"@keymanapp/models-types": "^15.0.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/web-utils": "^15.0.68",
"@keymanapp/keyboard-processor": "^15.0.69",
"@keymanapp/lexical-model-layer": "^15.0.69",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69",
"eventemitter3": "^4.0.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/keyboard-processor",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/keyboard-processor",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/resources-gosh": "^15.0.69",
"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.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/web-utils": "^15.0.68",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69",
"@types/node": "^11.9.4"
}
}

View file

@ -29,6 +29,7 @@ namespace com.keyman.keyboards {
private baseKeyEvent: text.KeyEvent;
isMnemonic: boolean = false;
proportionalPad: number;
proportionalX: number;
proportionalWidth: number;
@ -286,6 +287,12 @@ namespace com.keyman.keyboards {
* and are intended for use with layout testing (while headless) in the future.
*/
let setProportions = function(key: ActiveKey, padPc: number, keyPc: number, totalPc: number) {
key.proportionalPad = padPc;
key.proportionalWidth = keyPc;
key.proportionalX = (totalPc + padPc + (keyPc/2));
}
// Calculate percentage-based scalings by summing defined widths and scaling each key to %.
// Save each percentage key width as a separate member (do *not* overwrite layout specified width!)
var keyPercent: number, padPercent: number, totalPercent=0;
@ -296,9 +303,7 @@ namespace com.keyman.keyboards {
keys[j]['padpc']=padPercent;
// compute center's default x-coord (used in headless modes)
(<ActiveKey> keys[j]).proportionalX = (totalPercent + padPercent + (keyPercent/2));
(<ActiveKey> keys[j]).proportionalWidth = keyPercent;
setProportions(keys[j] as ActiveKey, padPercent, keyPercent, totalPercent);
totalPercent += padPercent+keyPercent;
}
@ -314,9 +319,7 @@ namespace com.keyman.keyboards {
keys[0]['padpc']=1-totalPercent;
// compute center's default x-coord (used in headless modes)
(<ActiveKey> keys[0]).proportionalX = ((totalPercent - rightMargin) - keyPercent/2);
(<ActiveKey> keys[0]).proportionalWidth = keyPercent;
setProportions(keys[0] as ActiveKey, padPercent, keyPercent, totalPercent);
} else if(keys.length > 0) {
let j=keys.length-1;
padPercent=parseInt(keys[j]['pad'],10)/totalWidth;
@ -325,8 +328,7 @@ namespace com.keyman.keyboards {
keys[j]['widthpc'] = keyPercent = 1-totalPercent;
// compute center's default x-coord (used in headless modes)
(<ActiveKey> keys[j]).proportionalX = (1 - rightMargin) - keyPercent/2;
(<ActiveKey> keys[j]).proportionalWidth = keyPercent;
setProportions(keys[j] as ActiveKey, padPercent, keyPercent, totalPercent);
}
// Add class functions to the existing layout object, allowing it to act as an ActiveLayout.

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/recorder-core",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/recorder-core",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/models-types": "^15.0.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/web-utils": "^15.0.68"
"@keymanapp/keyboard-processor": "^15.0.69",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69"
},
"devDependencies": {
"typescript": "^3.8.3"

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-sentry-manager",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-sentry-manager",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/web-environment": "^15.0.69",
"@sentry/browser": "^5.27.4"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-utils",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-utils",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/resources-gosh": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@types/node": "^14.0.5",
"typescript": "^3.8.3"
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-templates",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-templates",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/web-utils": "^15.0.68",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69",
"@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.68"
"@keymanapp/models-wordbreakers": "^15.0.69"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-types",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-types",
"version": "15.0.68",
"version": "15.0.69",
"description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.",
"types": "./index.d.ts",
"scripts": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-wordbreakers",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/models-wordbreakers",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/models-types": "^15.0.69",
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"chai": "^4.3.4",

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-layer",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-layer",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/resources-gosh": "^15.0.68",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/resources-gosh": "^15.0.69",
"@types/node": "^10.17.21",
"chai": "^4.3.4",
"karma": "^6.3.2",
@ -46,10 +46,10 @@
"typescript": "^3.8.3"
},
"dependencies": {
"@keymanapp/models-templates": "^15.0.68",
"@keymanapp/models-wordbreakers": "^15.0.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/web-utils": "^15.0.68",
"@keymanapp/models-templates": "^15.0.69",
"@keymanapp/models-wordbreakers": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69",
"es6-shim": "^0.35.5",
"string.prototype.codepointat": "^0.2.1",
"string.prototype.startswith": "^0.2.0"

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-compiler",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/lexical-model-compiler",
"version": "15.0.68",
"version": "15.0.69",
"description": "Keyman Developer lexical model compiler",
"keywords": [
"keyboard",
@ -37,14 +37,14 @@
"node": ">=12.0.0"
},
"dependencies": {
"@keymanapp/models-types": "^15.0.68",
"@keymanapp/models-types": "^15.0.69",
"commander": "^3.0.0",
"typescript": "^3.8.3",
"xml2js": "^0.4.19"
},
"devDependencies": {
"@keymanapp/models-templates": "^15.0.68",
"@keymanapp/models-wordbreakers": "^15.0.68",
"@keymanapp/models-templates": "^15.0.69",
"@keymanapp/models-wordbreakers": "^15.0.69",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^10.14.6",

View file

@ -20,5 +20,5 @@
"ts-node",
"typescript"
],
"version": "15.0.68"
"version": "15.0.69"
}

View file

@ -832,7 +832,8 @@ ibus_keyman_engine_process_key_event (IBusEngine *engine,
g_message("Saving keyboard option to DConf");
// Load the current keyboard options from DConf
keyman_put_options_todconf(keyman->kb_name, keyman->kb_name,
action_items[i].option->key, action_items[i].option->value);
(gchar *)action_items[i].option->key,
(gchar *)action_items[i].option->value);
}
}
break;

View file

@ -437,7 +437,7 @@ keyman_put_options_todconf(gchar *package_id,
if (child_settings != NULL)
{
g_message("writing keyboard options to DConf");
g_settings_set_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY, options);
g_settings_set_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY, (const gchar *const *)options);
}
g_object_unref(G_OBJECT(child_settings));

View file

@ -1,5 +1,5 @@
{
"name": "@keymanapp/resources-gosh",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/resources-gosh",
"version": "15.0.68",
"version": "15.0.69",
"description": "Good Ol' Shell",
"author": "Marc Durdin <marc@keyman.com> (https://github.com/mcdurdin)",
"contributors": [

View file

@ -1,5 +1,5 @@
{
"name": "@keymanapp/web-environment",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 1
}

View file

@ -1,6 +1,6 @@
{
"name": "@keymanapp/web-environment",
"version": "15.0.68",
"version": "15.0.69",
"description": "A compilation utility for passing select environment variables into our TS builds",
"author": "Joshua Horton <joshua_horton@sil.org> (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.68"
"@keymanapp/resources-gosh": "^15.0.69"
}
}

3
web/.gitignore vendored
View file

@ -1,9 +1,6 @@
# Legacy build folders.
output/
build/
embedded/
!source/**/embedded
# Current build folders.
intermediate/

2
web/package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "keyman",
"version": "15.0.68",
"version": "15.0.69",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "keyman",
"version": "15.0.68",
"version": "15.0.69",
"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.68",
"@keymanapp/web-sentry-manager": "^15.0.68",
"@keymanapp/resources-gosh": "^15.0.69",
"@keymanapp/web-sentry-manager": "^15.0.69",
"@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.68",
"@keymanapp/keyboard-processor": "^15.0.68",
"@keymanapp/lexical-model-layer": "^15.0.68",
"@keymanapp/models-types": "^15.0.68",
"@keymanapp/recorder-core": "^15.0.68",
"@keymanapp/web-environment": "^15.0.68",
"@keymanapp/web-utils": "^15.0.68",
"@keymanapp/input-processor": "^15.0.69",
"@keymanapp/keyboard-processor": "^15.0.69",
"@keymanapp/lexical-model-layer": "^15.0.69",
"@keymanapp/models-types": "^15.0.69",
"@keymanapp/recorder-core": "^15.0.69",
"@keymanapp/web-environment": "^15.0.69",
"@keymanapp/web-utils": "^15.0.69",
"@types/node": "^11.9.4",
"es6-shim": "^0.35.5",
"eventemitter3": "^4.0.0"

View file

@ -1,26 +1,5 @@
namespace com.keyman.osk {
export class PreProcessor {
static _GetClickEventProperties(e: keyboards.ActiveKey, Lelem: HTMLElement): text.KeyEvent {
let keyman = com.keyman.singleton;
let core = keyman.core;
// Start: mirrors _GetKeyEventProperties
// First check the virtual key, and process shift, control, alt or function keys
let Lkc = e.constructKeyEvent(core.keyboardProcessor, keyman.util.device.coreSpec);
// If it's actually a state key modifier, trigger its effects immediately, as KeyboardEvents would do the same.
switch(Lkc.kName) {
case 'K_CAPS':
case 'K_NUMLOCK':
case 'K_SCROLL':
core.keyboardProcessor.stateKeys[Lkc.kName] = ! core.keyboardProcessor.stateKeys[Lkc.kName];
}
// End - mirrors _GetKeyEventProperties
return Lkc;
}
/**
* Simulate a keystroke according to the touched keyboard button element
*
@ -30,7 +9,17 @@ namespace com.keyman.osk {
*
* @param {Object} e element touched (or clicked)
*/
static clickKey(e: osk.KeyElement, touch?: Touch, layerId?: string, keyDistribution?: text.KeyDistribution) {
static clickKey(e: osk.KeyElement, touch?: Touch) {
let keyman = com.keyman.singleton;
let Lkc = keyman['osk'].vkbd.initKeyEvent(e, touch);
if(!Lkc) {
return true;
}
return this.raiseKeyEvent(Lkc);
}
static raiseKeyEvent(keyEvent: text.KeyEvent) {
let keyman = com.keyman.singleton;
var Lelem = keyman.domManager.getLastActiveElement();
@ -38,9 +27,6 @@ namespace com.keyman.osk {
// Handle any DOM state management related to click inputs.
let outputTarget = dom.Utils.getOutputTarget(Lelem);
keyman.domManager.initActiveElement(Lelem);
// Turn off key highlighting (or preview)
keyman['osk'].vkbd.highlightKey(e,false);
// Clear any cached codepoint data; we can rebuild it if it's unchanged.
outputTarget.invalidateSelection();
@ -48,24 +34,6 @@ namespace com.keyman.osk {
// Deleting matched deadkeys here seems to correct some of the issues. (JD 6/6/14)
outputTarget.deadkeys().deleteMatched(); // Delete any matched deadkeys before continuing
// Future note: we need to refactor osk.OSKKeySpec to instead be a 'tag field' for
// keyboards.ActiveKey. (Prob with generics, allowing the Web-only parts to
// be fully specified within the tag.)
//
// Would avoid the type shenanigans needed here because of our current type-abuse setup
// for key spec tracking.
let keySpec = (e['key'] ? e['key'].spec : null) as unknown as keyboards.ActiveKey;
if(!keySpec) {
console.error("OSK key with ID '" + e.id + "', keyID '" + e.keyId + "' missing needed specification");
return true;
}
let Lkc = PreProcessor._GetClickEventProperties(keySpec, Lelem);
if(keyman.core.languageProcessor.isActive) {
Lkc.source = touch;
Lkc.keyDistribution = keyDistribution;
}
if(!keyman.isEmbedded) {
keyman.uiManager.setActivatingUI(true);
com.keyman.dom.DOMEventHandlers.states._IgnoreNextSelChange = 100;
@ -73,7 +41,7 @@ namespace com.keyman.osk {
com.keyman.dom.DOMEventHandlers.states._IgnoreNextSelChange = 0;
}
let retVal = PreProcessor.handleClick(Lkc, outputTarget, e);
let retVal = PreProcessor.handleClick(keyEvent, outputTarget, null);
// Now that processing is done, we can do a bit of post-processing, too.
keyman.uiManager.setActivatingUI(false); // I2498 - KeymanWeb OSK does not accept clicks in FF when using automatic UI
@ -87,7 +55,7 @@ namespace com.keyman.osk {
// after the KeyEvent object has been properly instantiated. This should help catch any
// mutual last-minute DOM-side interactions before passing control to the processor... such as
// the UI-control command keys as seen below.
static handleClick(Lkc: text.KeyEvent, outputTarget: text.OutputTarget, e: KeyElement) {
static handleClick(Lkc: text.KeyEvent, outputTarget: text.OutputTarget, e: osk.KeyElement) {
let keyman = com.keyman.singleton;
// Exclude menu and OSK hide keys from normal click processing
if(Lkc.kName == 'K_LOPT' || Lkc.kName == 'K_ROPT') {

View file

@ -1,6 +1,6 @@
/// <reference path="preProcessor.ts" />
/// <reference path="utils.ts" />
/// <reference path="abstractions.ts" />
/// <reference path="keytip.interface.ts" />
/// <reference path="browser/keytip.ts" />
/// <reference path="browser/subkeyPopup.ts" />
@ -872,7 +872,7 @@ namespace com.keyman.osk {
var n: number, i: number, j: number;
var layers: keyboards.LayoutLayer[], gDiv: HTMLDivElement;
var rowHeight: number, rDiv: HTMLDivElement;
var keys: keyboards.LayoutKey[], key: keyboards.LayoutKey, rs: CSSStyleDeclaration, gs: CSSStyleDeclaration;
var keys: keyboards.ActiveKey[], key: keyboards.ActiveKey, rs: CSSStyleDeclaration, gs: CSSStyleDeclaration;
layers=layout['layer'];
@ -966,49 +966,16 @@ namespace com.keyman.osk {
// Overwrite the previously-computed percent.
// NB: the 'percent' suffix is historical, units are percent on desktop devices, but pixels on touch devices
// All key widths and paddings are rounded for uniformity
var keyPercent: number, padPercent: number, totalPercent=0;
for(j=0; j<keys.length-1; j++) {
keyPercent = keys[j]['widthpc'] * objectWidth;
keys[j]['widthpc']=keyPercent;
padPercent = keys[j]['padpc'] * objectWidth;
keys[j]['padpc']=padPercent;
// Recompute center's x-coord with exact, in-browser values.
(<keyboards.ActiveKey> keys[j]).proportionalX = (totalPercent + padPercent + (keyPercent/2))/objectWidth;
(<keyboards.ActiveKey> keys[j]).proportionalWidth = keyPercent / objectWidth;
totalPercent += padPercent+keyPercent;
}
// Allow for right OSK margin (15 layout units)
let rightMargin = keyboards.ActiveKey.DEFAULT_RIGHT_MARGIN*objectWidth/layer.totalWidth;
totalPercent += rightMargin;
// If a single key, and padding is negative, add padding to right align the key
if(keys.length == 1 && parseInt(keys[0]['pad'],10) < 0) {
keyPercent = keys[0]['widthpc'] * objectWidth;
keys[0]['widthpc']=keyPercent;
totalPercent += keyPercent;
keys[0]['padpc']=(objectWidth-totalPercent);
// Recompute center's x-coord with exact, in-browser values.
(<keyboards.ActiveKey> keys[0]).proportionalX = (totalPercent - rightMargin - keyPercent/2)/objectWidth;
(<keyboards.ActiveKey> keys[0]).proportionalWidth = keyPercent / objectWidth;
} else if(keys.length > 0) {
j=keys.length-1;
padPercent = keys[j]['padpc'] * objectWidth;
keys[j]['padpc']=padPercent;
totalPercent += padPercent;
keys[j]['widthpc']= keyPercent = (objectWidth-totalPercent);
// Recompute center's x-coord with exact, in-browser values.
(<keyboards.ActiveKey> keys[j]).proportionalX = (objectWidth - rightMargin - keyPercent/2)/objectWidth;
(<keyboards.ActiveKey> keys[j]).proportionalWidth = keyPercent / objectWidth;
for(j=0; j<keys.length; j++) {
key = keys[j];
// TODO: reinstate rounding?
key['widthpc'] = key.proportionalWidth * objectWidth;
key['padpc'] = key.proportionalPad * objectWidth;
}
}
//Create the key square (an outer DIV) for each key element with padding, and an inner DIV for the button (btn)
totalPercent=0;
var totalPercent=0;
for(j=0; j<keys.length; j++) {
key=keys[j];
@ -1181,7 +1148,7 @@ namespace com.keyman.osk {
// Special function keys need immediate action
if(keyName == 'K_LOPT' || keyName == 'K_ROPT') {
window.setTimeout(function(this: VisualKeyboard){
PreProcessor.clickKey(key);
this.modelKeyClick(key);
// Because we immediately process the key, we need to re-highlight it after the click.
this.highlightKey(key, true);
// Highlighting'll be cleared automatically later.
@ -1191,10 +1158,9 @@ namespace com.keyman.osk {
// Also backspace, to allow delete to repeat while key held
} else if(keyName == 'K_BKSP') {
let touchProbabilities = this.getTouchProbabilities(e.changedTouches[0]);
// While we could inline the execution of the delete key here, we lose the ability to
// record the backspace key if we do so.
PreProcessor.clickKey(key, e.changedTouches[0], this.layerId, touchProbabilities);
this.modelKeyClick(key, e.changedTouches[0]);
this.deleteKey = key;
this.deleting = window.setTimeout(this.repeatDelete,500);
this.keyPending = null;
@ -1202,8 +1168,7 @@ namespace com.keyman.osk {
} else {
if(this.keyPending) {
this.highlightKey(this.keyPending, false);
let touchProbabilities = this.getTouchProbabilities(this.touchPending);
PreProcessor.clickKey(this.keyPending, this.touchPending, this.layerId, touchProbabilities);
this.modelKeyClick(this.keyPending, this.touchPending);
this.clearPopup();
// Decrement the number of unreleased touch points to prevent
// sending the keystroke again when the key is actually released
@ -1276,8 +1241,7 @@ namespace com.keyman.osk {
// Output character unless moved off key
if(this.keyPending.className.indexOf('hidden') < 0 && tc > 0 && !beyondEdge) {
let touchProbabilities = this.getTouchProbabilities(e.changedTouches[0]);
PreProcessor.clickKey(this.keyPending, e.changedTouches[0], this.layerId, touchProbabilities);
this.modelKeyClick(this.keyPending, e.changedTouches[0]);
}
this.clearPopup();
this.keyPending = null;
@ -1556,7 +1520,7 @@ namespace com.keyman.osk {
**/
repeatDelete: () => void = function(this: VisualKeyboard) {
if(this.deleting) {
PreProcessor.clickKey(this.deleteKey);
this.modelKeyClick(this.deleteKey);
this.deleting = window.setTimeout(this.repeatDelete,100);
}
}.bind(this);
@ -1574,6 +1538,57 @@ namespace com.keyman.osk {
}
//#endregion
modelKeyClick(e: osk.KeyElement, touch?: Touch) {
let keyEvent = this.initKeyEvent(e, touch);
// TODO: convert into an actual event, raised by the VisualKeyboard.
// Its code is intended to lie outside of the OSK-Core library/module.
PreProcessor.raiseKeyEvent(keyEvent);
}
initKeyEvent(e: osk.KeyElement, touch?: Touch) {
// Turn off key highlighting (or preview)
this.highlightKey(e,false);
let core = com.keyman.singleton.core; // only singleton-based ref currently needed here.
// Future note: we need to refactor osk.OSKKeySpec to instead be a 'tag field' for
// keyboards.ActiveKey. (Prob with generics, allowing the Web-only parts to
// be fully specified within the tag.)
//
// Would avoid the type shenanigans needed here because of our current type-abuse setup
// for key spec tracking.
let keySpec = (e['key'] ? e['key'].spec : null) as unknown as keyboards.ActiveKey;
if(!keySpec) {
console.error("OSK key with ID '" + e.id + "', keyID '" + e.keyId + "' missing needed specification");
return null;
}
// Start: mirrors _GetKeyEventProperties
// First check the virtual key, and process shift, control, alt or function keys
let Lkc = keySpec.constructKeyEvent(core.keyboardProcessor, this.device.coreSpec);
// If it's actually a state key modifier, trigger its effects immediately, as KeyboardEvents would do the same.
switch(Lkc.kName) {
case 'K_CAPS':
case 'K_NUMLOCK':
case 'K_SCROLL':
core.keyboardProcessor.stateKeys[Lkc.kName] = ! core.keyboardProcessor.stateKeys[Lkc.kName];
}
// End - mirrors _GetKeyEventProperties
if(core.languageProcessor.isActive && touch) {
Lkc.source = touch;
Lkc.keyDistribution = this.getTouchProbabilities(touch);;
}
// Return the event object.
return Lkc;
}
// cancel = function(e) {} //cancel event is never generated by iOS
/**
@ -1846,7 +1861,7 @@ namespace com.keyman.osk {
// Process as click if mouse button released anywhere over key
if(util.eventType(e) == 'mouseup') {
if(key.id == this.currentKey) {
PreProcessor.clickKey(key);
this.modelKeyClick(key);
}
this.currentKey='';
}

View file

@ -29,6 +29,7 @@ namespace com.keyman {
export namespace osk {
export declare var PreProcessor: any;
export declare var VisualKeyboard: any;
}
}
@ -199,15 +200,15 @@ namespace KMWRecorder {
return retVal;
}
var _originalClickKey = com.keyman.osk.PreProcessor.clickKey; //.bind(keyman.osk);
com.keyman.osk.PreProcessor.clickKey = function(e) {
var _originalModelKeyClick = com.keyman.osk.VisualKeyboard.prototype.modelKeyClick; //.bind(keyman.osk);
com.keyman.osk.VisualKeyboard.prototype.modelKeyClick = function(e, touch) {
let in_output = com.keyman.dom.Utils.getOutputTarget(recordingElement);
if(!in_output || com.keyman.dom.DOMEventHandlers.states.activeElement != in_output.getElement()) {
return _originalClickKey(e);
return _originalModelKeyClick.call(this, e, touch);
}
let event = KMWRecorder.Scribe.recordOSKEvent(e);
var retVal = _originalClickKey(e);
var retVal = _originalModelKeyClick.call(this, e, touch);
let recording = Scribe.recordKeystroke(recorderScribe._currentKeyEvent, event);
@ -254,9 +255,9 @@ namespace KMWRecorder {
}
var _originalProcessKeyEvent = keyman.core.processKeyEvent.bind(keyman.core);
keyman.core.processKeyEvent = function(keyEvent /* com.keyman.text.KeyEvent */) {
keyman.core.processKeyEvent = function(keyEvent /* com.keyman.text.KeyEvent */, target /* com.keyman.text.OutputTarget */) {
recorderScribe._currentKeyEvent = keyEvent;
return _originalProcessKeyEvent(keyEvent);
return _originalProcessKeyEvent(keyEvent, target);
}
}
}