spiegel-keyman/common/web/input-processor/src/correctionLayout.ts
2024-05-31 13:58:31 +07:00

111 lines
No EOL
3.7 KiB
TypeScript

import { ActiveKey, ActiveKeyBase, ActiveLayer, ActiveRow, Codes } from "@keymanapp/keyboard-processor";
/**
* Defines correction-layout mappings for keys to be considered by
* the fat-finger algorithm and its related calculations, which are
* used to determine the "closest keys" for corrections.
*/
export interface CorrectionLayoutEntry {
/**
* The ID of the key corresponding to this entry.
*/
readonly keySpec: ActiveKeyBase;
/**
* Represents the center x coordinate of the key based on the coordinate system
* with the keyboard's layout bounding box mapped to a box from <0, 0> to <1, 1>.
*/
readonly centerX: number;
/**
* Represents the center y coordinate of the key based on the coordinate system
* with the keyboard's layout bounding box mapped to a box from <0, 0> to <1, 1>.
*/
readonly centerY: number;
/**
* Represents the key's width based on the coordinate system with the
* keyboard's layout bounding box mapped to a box from <0, 0> to <1, 1>.
*/
readonly width: number;
/**
* Represents the key's height based on the coordinate system with the
* keyboard's layout bounding box mapped to a box from <0, 0> to <1, 1>.
*/
readonly height: number;
}
export interface CorrectionLayout {
/**
* Defines the mappings of each key to be considered by a key-correction
* algorithm. The key's bounding box should be defined relative to its
* container's bounding box, with both mapped to a coordinate system from
* <0, 0> to <1, 1> - a unit square.
*/
keys: CorrectionLayoutEntry[];
/**
* The ratio of the keyboard's horizontal scale to its vertical scale.
* For a 400 x 200 keyboard, should be 2.
*/
kbdScaleRatio: number;
}
// Not compatible with subkeys - their layout data is only determined (presently) at runtime.
export class CorrectiveBaseKeyLayout implements CorrectionLayoutEntry {
readonly keySpec: ActiveKey;
readonly centerX: number;
readonly centerY: number;
readonly width: number;
readonly height: number;
constructor(layer: ActiveLayer, row: ActiveRow, key: ActiveKey) {
this.keySpec = key;
this.centerX = key.proportionalX;
this.centerY = row.proportionalY;
this.width = key.proportionalWidth;
this.height = layer.rowProportionalHeight;
}
}
/**
* Indicates whether or not the specified key should be considered as a valid
* key-correction target during fat-finger operations.
* @param key
* @returns `true` if valid, `false` if invalid.
*/
export function correctionKeyFilter(key: ActiveKeyBase): boolean {
// If the key lacks an ID, just skip it. Sometimes used for padding.
if(!key.baseKeyID) {
return false;
// Attempt to filter out known non-output keys.
// Results in a more optimized distribution.
} else if(Codes.isFrameKey(key.baseKeyID)) {
return false;
} else if(key.isPadding) { // to the user, blank / padding keys do not exist.
return false;
} else {
return true;
}
}
/**
* Builds the corrective layout object corresponding to the specified keyboard layer,
* as needed for use of our key-correction algorithms.
*
* @param layer The layer spec to reference for key corrections.
* @param kbdScaleRatio The ratio of the keyboard's horizontal scale to its vertical scale.
* For a 400 x 200 keyboard, should be 2.
*/
export function buildCorrectiveLayout(layer: ActiveLayer, kbdScaleRatio: number) {
return {
keys: layer.row.map((row) => {
return row.key.map((key) => new CorrectiveBaseKeyLayout(layer, row, key));
// ... and flatten/merge the resulting arrays.
}).reduce((flattened, rowEntries) => flattened.concat(rowEntries), [])
.filter((entry) => correctionKeyFilter(entry.keySpec)),
kbdScaleRatio: kbdScaleRatio
};
}