chore(web): post-refactor fixes to keyboard-processor, input-processor unit tests

This commit is contained in:
Joshua A. Horton 2023-01-25 09:14:23 +07:00
parent f94cd9f5dd
commit ffb614f52c
6 changed files with 170 additions and 20 deletions

View file

@ -96,7 +96,7 @@ describe('InputProcessor', function() {
core.activeKeyboard = keyboard;
let layout = keyboard.layout(utils.DeviceSpec.FormFactor.Phone);
let key = layout.getLayer('default').getKey('K_A');
let event = key.constructKeyEvent(core.keyboardProcessor, device);
let event = keyboard.constructKeyEvent(key, device, core.keyboardProcessor.stateKeys);
let behavior = core.processKeyEvent(event, context);
assert.isNotNull(behavior);
@ -115,7 +115,7 @@ describe('InputProcessor', function() {
core.activeKeyboard = keyboard;
let layout = keyboard.layout(utils.DeviceSpec.FormFactor.Phone);
let key = layout.getLayer('default').getKey('K_A');
let event = key.constructKeyEvent(core.keyboardProcessor, device);
let event = keyboard.constructKeyEvent(key, device, core.keyboardProcessor.stateKeys);
let behavior = core.processKeyEvent(event, context);
assert.isNotNull(behavior);
@ -132,7 +132,7 @@ describe('InputProcessor', function() {
let layout = keyboard.layout(utils.DeviceSpec.FormFactor.Phone);
let key = layout.getLayer('default').getKey('K_A');
key.keyDistribution = testDistribution;
let event = key.constructKeyEvent(core.keyboardProcessor, device);
let event = keyboard.constructKeyEvent(key, device, core.keyboardProcessor.stateKeys);
let behavior = core.processKeyEvent(event, context);
assert.isNotNull(behavior);
@ -155,7 +155,7 @@ describe('InputProcessor', function() {
let layout = keyboard.layout(utils.DeviceSpec.FormFactor.Phone);
let key = layout.getLayer('default').getKey('K_A');
key.keyDistribution = testDistribution;
let event = key.constructKeyEvent(core.keyboardProcessor, device);
let event = keyboard.constructKeyEvent(key, device, core.keyboardProcessor.stateKeys);
let behavior = core.processKeyEvent(event, context);
assert.isNotNull(behavior);

View file

@ -1,5 +1,5 @@
import Codes from "../text/codes.js";
import KeyEvent from "../text/keyEvent.js";
import KeyEvent, { KeyEventSpec } from "../text/keyEvent.js";
import KeyMapping from "../text/keyMapping.js";
import type { KeyDistribution } from "../text/keyEvent.js";
import type { LayoutKey, LayoutRow, LayoutLayer, LayoutFormFactor, ButtonClass } from "./defaultLayouts.js";
@ -247,8 +247,7 @@ export class ActiveKey implements LayoutKey {
// Start: mirrors _GetKeyEventProperties
// First check the virtual key, and process shift, control, alt or function keys
let Lkc: KeyEvent = new KeyEvent();
let props = {
let props: KeyEventSpec = {
// Override key shift state if specified for key in layout (corrected for popup keys KMEW-93)
Lmodifiers: Codes.getModifierState(layer),
Lstates: Codes.getStateFromLayer(layer),
@ -263,9 +262,7 @@ export class ActiveKey implements LayoutKey {
isSynthetic: true
};
for(let key in props) {
Lkc[key] = props[key];
}
let Lkc: KeyEvent = new KeyEvent(props);
if(layout.keyboard) {
let keyboard = layout.keyboard;

View file

@ -16,11 +16,50 @@ import DefaultOutput from './defaultOutput.js';
// Defined here to avoid compilation issues.
export type KeyDistribution = {keyId: string, p: number}[];
export interface KeyEventSpec {
Lcode: number;
Lstates: number;
LmodifierChange?: boolean;
Lmodifiers: number;
LisVirtualKey: boolean;
vkCode: number;
kName: string;
kLayer?: string; // The key's layer property
kbdLayer?: string; // The virtual keyboard's active layer
kNextLayer?: string;
/**
* Marks the active keyboard at the time that this KeyEvent was generated by the user.
*
* Note: this is NOT equivalent to the active keyboard at the time that the event handler begins
* processing! It should be set via closure (or similar) on the event handler that can 100%
* guarantee that the keyboard instance known to the handler has not changed during JS execution
* since the user's interaction that raised the event.
*/
srcKeyboard?: Keyboard;
// Holds relevant event properties leading to construction of this KeyEvent.
source?: any; // Technically, KeyEvent|MouseEvent|Touch - but those are DOM types that must be kept out of headless mode.
// Holds a generated fat-finger distribution (when appropriate)
keyDistribution?: KeyDistribution;
/**
* The device model for web-core to follow when processing the keystroke.
*/
device: DeviceSpec;
/**
* `true` if this event was produced by sources other than a DOM-based KeyboardEvent.
*/
isSynthetic?: boolean;
}
/**
* This class is defined within its own file so that it can be loaded by code outside of KMW without
* having to actually load the entirety of KMW.
*/
export default class KeyEvent {
export default class KeyEvent implements KeyEventSpec {
Lcode: number;
Lstates: number;
LmodifierChange?: boolean;
@ -57,11 +96,24 @@ export default class KeyEvent {
*/
isSynthetic: boolean = true;
public constructor(keyEventSpec: KeyEventSpec) {
for(let key in keyEventSpec) {
if(keyEventSpec[key] !== undefined) {
this[key] = keyEventSpec[key];
}
}
}
public static constructNullKeyEvent(device: DeviceSpec): KeyEvent {
const keyEvent = new KeyEvent();
keyEvent.Lcode = 0;
keyEvent.kName = '';
keyEvent.device = device;
const keyEvent = new KeyEvent({
Lcode: 0,
kName: '',
device: device,
Lstates: undefined,
Lmodifiers: undefined,
vkCode: undefined,
LisVirtualKey: undefined
});
return keyEvent;
}
@ -86,7 +138,7 @@ export default class KeyEvent {
if(this.Lcode != Codes.keyCodes['K_SPACE']) {
// So long as the key name isn't prefixed with 'U_', we'll get a default mapping based on the Lcode value.
// We need to determine the mnemonic base character - for example, SHIFT + K_PERIOD needs to map to '>'.
let mappingEvent: KeyEvent = new KeyEvent();
let mappingEvent: KeyEvent = new KeyEvent(this);
for(let key in (this as KeyEvent)) {
mappingEvent[key] = this[key];
}

View file

@ -9,7 +9,7 @@ import {
} from "./index.js";
import Keyboard from "@keymanapp/keyboard-processor/build/obj/keyboards/keyboard.js";
import type KeyEvent from "@keymanapp/keyboard-processor/build/obj/text/keyEvent.js";
import KeyEvent, { KeyEventSpec } from "@keymanapp/keyboard-processor/build/obj/text/keyEvent.js";
import KeyboardProcessor from "@keymanapp/keyboard-processor/build/obj/text/keyboardProcessor.js";
import type OutputTarget from "@keymanapp/keyboard-processor/build/obj/text/outputTarget.js";
import { Mock } from "@keymanapp/keyboard-processor/build/obj/text/outputTarget.js";
@ -64,7 +64,7 @@ export default class NodeProctor extends Proctor {
if(sequence instanceof RecordedKeystrokeSequence) {
for(let keystroke of sequence.inputs) {
let keyEvent: KeyEvent;
let keyEvent: KeyEventSpec;
if(keystroke instanceof RecordedPhysicalKeystroke) {
// Use the keystroke's stored data to reconstruct the KeyEvent.
keyEvent = {
@ -80,7 +80,7 @@ export default class NodeProctor extends Proctor {
}
} else if(keystroke instanceof RecordedSyntheticKeystroke) {
let key = this.keyboard.layout(this.device.formFactor).getLayer(keystroke.layer).getKey(keystroke.keyName);
keyEvent = key.constructKeyEvent(processor, this.device);
keyEvent = this.keyboard.constructKeyEvent(key, this.device, processor.stateKeys);
}
// Fill in the final details of the KeyEvent...
@ -90,7 +90,7 @@ export default class NodeProctor extends Proctor {
// We don't care too much about particularities of per-keystroke behavior yet.
// ... we _could_ if we wanted to, though. The framework is mostly in place;
// it's a matter of actually adding the feature.
let ruleBehavior = processor.processKeystroke(keyEvent, target);
let ruleBehavior = processor.processKeystroke(new KeyEvent(keyEvent), target);
if(this.debugMode) {
console.log(JSON.stringify(target, null, ' '));

View file

@ -3,6 +3,7 @@
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"module": "es6",
"moduleResolution": "Node",
"declaration": true,

100
package-lock.json generated
View file

@ -2247,6 +2247,33 @@
"color-support": "bin.js"
}
},
"node_modules/combine-source-map": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
"integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==",
"dev": true,
"dependencies": {
"convert-source-map": "~1.1.0",
"inline-source-map": "~0.6.0",
"lodash.memoize": "~3.0.3",
"source-map": "~0.5.3"
}
},
"node_modules/combine-source-map/node_modules/convert-source-map": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
"integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==",
"dev": true
},
"node_modules/combine-source-map/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -3980,6 +4007,24 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/inline-source-map": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
"integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==",
"dev": true,
"dependencies": {
"source-map": "~0.5.3"
}
},
"node_modules/inline-source-map/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -4580,6 +4625,12 @@
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
},
"node_modules/lodash.memoize": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==",
"dev": true
},
"node_modules/lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
@ -9309,6 +9360,32 @@
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"dev": true
},
"combine-source-map": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
"integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==",
"dev": true,
"requires": {
"convert-source-map": "~1.1.0",
"inline-source-map": "~0.6.0",
"lodash.memoize": "~3.0.3",
"source-map": "~0.5.3"
},
"dependencies": {
"convert-source-map": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
"integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"dev": true
}
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -10556,6 +10633,23 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"inline-source-map": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
"integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==",
"dev": true,
"requires": {
"source-map": "~0.5.3"
},
"dependencies": {
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"dev": true
}
}
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -11073,6 +11167,12 @@
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
},
"lodash.memoize": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==",
"dev": true
},
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",