From 2c2acbe8633165157561c29ee30df02eb6981e82 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 25 Jun 2024 18:49:35 +0200 Subject: [PATCH 1/2] refactor(web): refactor and harmonize constants Note that this adds the keyCodes > 50000 to `USVirtualKeyCodes`. Fixes: #8146 --- .../src/keyboards/defaultLayouts.ts | 18 ++-- .../src/keyboards/keyboard.ts | 24 +++-- .../src/keyboards/keyboardHarness.ts | 3 +- .../web/keyboard-processor/src/text/codes.ts | 97 +++++++------------ .../src/text/defaultRules.ts | 3 +- .../src/text/kbdInterface.ts | 13 +-- .../src/text/keyboardProcessor.ts | 39 ++++---- .../tests/node/chirality.js | 21 ++-- .../tests/node/non-positional-rules.js | 22 ++--- .../tests/node/specialized-backspace.js | 21 ++-- .../src/consts/modifier-key-constants.ts | 33 +++++++ .../types/src/consts/virtual-key-constants.ts | 5 +- common/web/types/src/kmx/kmx.ts | 31 +++--- common/web/types/src/main.ts | 4 +- .../app/browser/src/defaultBrowserRules.ts | 3 +- .../app/browser/src/hardwareEventKeyboard.ts | 26 ++--- web/src/engine/main/src/hardKeyboard.ts | 5 +- 17 files changed, 189 insertions(+), 179 deletions(-) create mode 100644 common/web/types/src/consts/modifier-key-constants.ts diff --git a/common/web/keyboard-processor/src/keyboards/defaultLayouts.ts b/common/web/keyboard-processor/src/keyboards/defaultLayouts.ts index 19f634f11c1..109da53a0e5 100644 --- a/common/web/keyboard-processor/src/keyboards/defaultLayouts.ts +++ b/common/web/keyboard-processor/src/keyboards/defaultLayouts.ts @@ -4,7 +4,7 @@ ***/ import { Version, deepCopy } from "@keymanapp/web-utils"; -import { TouchLayout } from "@keymanapp/common-types"; +import { ModifierKeyConstants, TouchLayout } from "@keymanapp/common-types"; import LayoutFormFactorSpec = TouchLayout.TouchLayoutPlatform; import LayoutLayerBase = TouchLayout.TouchLayoutLayer; @@ -349,31 +349,29 @@ export class Layouts { * Description Get name of layer from code, where the modifer order is determined by ascending bit-flag value. */ static getLayerId(m: number): string { - let modifierCodes = Codes.modifierCodes; - var s=''; if(m == 0) { return 'default'; } else { - if(m & modifierCodes['LCTRL']) { + if(m & ModifierKeyConstants.LCTRLFLAG) { s = (s.length > 0 ? s + '-' : '') + 'leftctrl'; } - if(m & modifierCodes['RCTRL']) { + if(m & ModifierKeyConstants.RCTRLFLAG) { s = (s.length > 0 ? s + '-' : '') + 'rightctrl'; } - if(m & modifierCodes['LALT']) { + if(m & ModifierKeyConstants.LALTFLAG) { s = (s.length > 0 ? s + '-' : '') + 'leftalt'; } - if(m & modifierCodes['RALT']) { + if(m & ModifierKeyConstants.RALTFLAG) { s = (s.length > 0 ? s + '-' : '') + 'rightalt'; } - if(m & modifierCodes['SHIFT']) { + if(m & ModifierKeyConstants.K_SHIFTFLAG) { s = (s.length > 0 ? s + '-' : '') + 'shift'; } - if(m & modifierCodes['CTRL']) { + if(m & ModifierKeyConstants.K_CTRLFLAG) { s = (s.length > 0 ? s + '-' : '') + 'ctrl'; } - if(m & modifierCodes['ALT']) { + if(m & ModifierKeyConstants.K_ALTFLAG) { s = (s.length > 0 ? s + '-' : '') + 'alt'; } return s; diff --git a/common/web/keyboard-processor/src/keyboards/keyboard.ts b/common/web/keyboard-processor/src/keyboards/keyboard.ts index ad804ef565a..5312d825a65 100644 --- a/common/web/keyboard-processor/src/keyboards/keyboard.ts +++ b/common/web/keyboard-processor/src/keyboards/keyboard.ts @@ -3,7 +3,7 @@ import { EncodedVisualKeyboard, LayoutSpec, Layouts } from "./defaultLayouts.js" import { ActiveKey, ActiveLayout, ActiveSubKey } from "./activeLayout.js"; import KeyEvent from "../text/keyEvent.js"; import type OutputTarget from "../text/outputTarget.js"; -import { TouchLayout } from "@keymanapp/common-types"; +import { ModifierKeyConstants, TouchLayout } from "@keymanapp/common-types"; type TouchLayoutSpec = TouchLayout.TouchLayoutPlatform & { isDefault?: boolean}; import type { ComplexKeyboardStore } from "../text/kbdInterface.js"; @@ -108,7 +108,7 @@ export type KeyboardObject = { KRTL?: boolean; /** * Keyboard Modifier BitMask: a set of bitflags indicating which modifiers - * the keyboard's rules utilize. See also: `Codes.modifierCodes`. + * the keyboard's rules utilize. See also: `ModifierKeyConstants`. */ KMBM?: number; /** @@ -420,8 +420,6 @@ export default class Keyboard { * @return {boolean} */ get emulatesAltGr(): boolean { - let modifierCodes = Codes.modifierCodes; - // If we're not chiral, we're not emulating. if(!this.isChiral) { return false; @@ -437,9 +435,9 @@ export default class Keyboard { return false; } - var emulationMask = modifierCodes['LCTRL'] | modifierCodes['LALT']; + var emulationMask = ModifierKeyConstants.LCTRLFLAG | ModifierKeyConstants.LALTFLAG; var unshiftedEmulationLayer = layers[Layouts.getLayerId(emulationMask)]; - var shiftedEmulationLayer = layers[Layouts.getLayerId(modifierCodes['SHIFT'] | emulationMask)]; + var shiftedEmulationLayer = layers[Layouts.getLayerId(ModifierKeyConstants.K_SHIFTFLAG | emulationMask)]; // buildDefaultLayout ensures that these are aliased to the original modifier set being emulated. // As a result, we can directly test for reference equality. @@ -447,12 +445,12 @@ export default class Keyboard { // This allows us to still return `true` after creating the layers for emulation; during keyboard // construction, the two layers should be null for AltGr emulation to succeed. if(unshiftedEmulationLayer != null && - unshiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'])]) { + unshiftedEmulationLayer != layers[Layouts.getLayerId(ModifierKeyConstants.RALTFLAG)]) { return false; } if(shiftedEmulationLayer != null && - shiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'] | modifierCodes['SHIFT'])]) { + shiftedEmulationLayer != layers[Layouts.getLayerId(ModifierKeyConstants.RALTFLAG | ModifierKeyConstants.K_SHIFTFLAG)]) { return false; } @@ -665,9 +663,9 @@ export default class Keyboard { * same for the other modifiers. */ Lkc.Lstates = 0; - Lkc.Lstates |= stateKeys['K_CAPS'] ? Codes.modifierCodes['CAPS'] : Codes.modifierCodes['NO_CAPS']; - Lkc.Lstates |= stateKeys['K_NUMLOCK'] ? Codes.modifierCodes['NUM_LOCK'] : Codes.modifierCodes['NO_NUM_LOCK']; - Lkc.Lstates |= stateKeys['K_SCROLL'] ? Codes.modifierCodes['SCROLL_LOCK'] : Codes.modifierCodes['NO_SCROLL_LOCK']; + Lkc.Lstates |= stateKeys['K_CAPS'] ? ModifierKeyConstants.CAPITALFLAG : ModifierKeyConstants.NOTCAPITALFLAG; + Lkc.Lstates |= stateKeys['K_NUMLOCK'] ? ModifierKeyConstants.NUMLOCKFLAG : ModifierKeyConstants.NOTNUMLOCKFLAG; + Lkc.Lstates |= stateKeys['K_SCROLL'] ? ModifierKeyConstants.SCROLLFLAG : ModifierKeyConstants.NOTSCROLLFLAG; } // Set LisVirtualKey to false to ensure that nomatch rule does fire for U_xxxx keys @@ -689,7 +687,7 @@ export default class Keyboard { // Handles modifier states when the OSK is emulating rightalt through the leftctrl-leftalt layer. if((Lkc.Lmodifiers & Codes.modifierBitmasks['ALT_GR_SIM']) == Codes.modifierBitmasks['ALT_GR_SIM'] && this.emulatesAltGr) { Lkc.Lmodifiers &= ~Codes.modifierBitmasks['ALT_GR_SIM']; - Lkc.Lmodifiers |= Codes.modifierCodes['RALT']; + Lkc.Lmodifiers |= ModifierKeyConstants.RALTFLAG; } } @@ -729,4 +727,4 @@ export default class Keyboard { const res=dict[keyName.toUpperCase()]; return res ? res : 0; } -} \ No newline at end of file +} diff --git a/common/web/keyboard-processor/src/keyboards/keyboardHarness.ts b/common/web/keyboard-processor/src/keyboards/keyboardHarness.ts index 02857cbeb8c..671c8fefd7c 100644 --- a/common/web/keyboard-processor/src/keyboards/keyboardHarness.ts +++ b/common/web/keyboard-processor/src/keyboards/keyboardHarness.ts @@ -14,8 +14,7 @@ export interface KeyboardKeymanGlobal { * Defines any public API points used by debug-compiled keyboards for human-readable * nomenclature in rules within a Keyman keyboard's script for keyboard rules. * - * Refer to C:\keymanapp\keyman\developer\src\tike\compile\CompileKeymanWeb.pas, - * TCompileKeymanWeb.JavaScript_SetupDebug. + * Refer to TCompileKeymanWeb.JavaScript_SetupDebug. */ export interface MinimalCodesInterface { readonly modifierCodes: typeof Codes.modifierCodes; diff --git a/common/web/keyboard-processor/src/text/codes.ts b/common/web/keyboard-processor/src/text/codes.ts index 26c10eb2d53..7f98b661891 100644 --- a/common/web/keyboard-processor/src/text/codes.ts +++ b/common/web/keyboard-processor/src/text/codes.ts @@ -1,31 +1,36 @@ -// TODO: Move to separate folder: 'codes' -// We should start splitting off code needed by keyboards even without a KeyboardProcessor active. +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Keyboard key codes and modifier bitmasks. + */ -// see also: common/web/types/src/kmx/kmx.ts +import { ModifierKeyConstants, USVirtualKeyCodes } from '@keymanapp/common-types'; const Codes = { - // Define Keyman Developer modifier bit-flags (exposed for use by other modules) - // Compare against /common/include/kmx_file.h. CTRL+F "#define LCTRLFLAG" to find the secton. modifierCodes: { - "LCTRL":0x0001, // LCTRLFLAG - "RCTRL":0x0002, // RCTRLFLAG - "LALT":0x0004, // LALTFLAG - "RALT":0x0008, // RALTFLAG - "SHIFT":0x0010, // K_SHIFTFLAG - "CTRL":0x0020, // K_CTRLFLAG - "ALT":0x0040, // K_ALTFLAG + ...ModifierKeyConstants, + + // Debug-mode keyboards compiled before Keyman 18.0 referenced the `ModifierKeyConstants` + // constants via the names established below. We must continue to support them, as they're + // essentially part of the keyboard API now. + "LCTRL": ModifierKeyConstants.LCTRLFLAG, + "RCTRL": ModifierKeyConstants.RCTRLFLAG, + "LALT": ModifierKeyConstants.LALTFLAG, + "RALT": ModifierKeyConstants.RALTFLAG, + "SHIFT": ModifierKeyConstants.K_SHIFTFLAG, + "CTRL": ModifierKeyConstants.K_CTRLFLAG, + "ALT": ModifierKeyConstants.K_ALTFLAG, // TENTATIVE: Represents command keys, which some OSes use for shortcuts we don't // want to block. No rule will ever target a modifier set with this bit set to 1. - "META":0x0080, // K_METAFLAG - "CAPS":0x0100, // CAPITALFLAG - "NO_CAPS":0x0200, // NOTCAPITALFLAG - "NUM_LOCK":0x0400, // NUMLOCKFLAG - "NO_NUM_LOCK":0x0800, // NOTNUMLOCKFLAG - "SCROLL_LOCK":0x1000, // SCROLLFLAG - "NO_SCROLL_LOCK":0x2000, // NOTSCROLLFLAG - "VIRTUAL_KEY":0x4000, // ISVIRTUALKEY - "VIRTUAL_CHAR_KEY":0x8000 // VIRTUALCHARKEY // Unused by KMW, but reserved for use by other Keyman engines. - + "META": ModifierKeyConstants.K_METAFLAG, + "CAPS": ModifierKeyConstants.CAPITALFLAG, + "NO_CAPS": ModifierKeyConstants.NOTCAPITALFLAG, + "NUM_LOCK": ModifierKeyConstants.NUMLOCKFLAG, + "NO_NUM_LOCK": ModifierKeyConstants.NOTNUMLOCKFLAG, + "SCROLL_LOCK": ModifierKeyConstants.SCROLLFLAG, + "NO_SCROLL_LOCK": ModifierKeyConstants.NOTSCROLLFLAG, + "VIRTUAL_KEY": ModifierKeyConstants.ISVIRTUALKEY, + "VIRTUAL_CHAR_KEY": ModifierKeyConstants.VIRTUALCHARKEY // Unused by KMW, but reserved for use by other Keyman engines. // Note: keys_mod_other = 0x10000, used by KMX+ for the // other modifier flag in layers, > 16 bit so not available here. // See keys_mod_other in keyman_core_ldml.ts @@ -50,35 +55,7 @@ const Codes = { // Define standard keycode numbers (exposed for use by other modules) keyCodes: { - "K_BKSP":8,"K_TAB":9,"K_ENTER":13, - "K_SHIFT":16,"K_CONTROL":17,"K_ALT":18,"K_PAUSE":19,"K_CAPS":20, - "K_ESC":27,"K_SPACE":32,"K_PGUP":33, - "K_PGDN":34,"K_END":35,"K_HOME":36,"K_LEFT":37,"K_UP":38, - "K_RIGHT":39,"K_DOWN":40,"K_SEL":41,"K_PRINT":42,"K_EXEC":43, - "K_INS":45,"K_DEL":46,"K_HELP":47,"K_0":48, - "K_1":49,"K_2":50,"K_3":51,"K_4":52,"K_5":53,"K_6":54,"K_7":55, - "K_8":56,"K_9":57,"K_A":65,"K_B":66,"K_C":67,"K_D":68,"K_E":69, - "K_F":70,"K_G":71,"K_H":72,"K_I":73,"K_J":74,"K_K":75,"K_L":76, - "K_M":77,"K_N":78,"K_O":79,"K_P":80,"K_Q":81,"K_R":82,"K_S":83, - "K_T":84,"K_U":85,"K_V":86,"K_W":87,"K_X":88,"K_Y":89,"K_Z":90, - "K_NP0":96,"K_NP1":97,"K_NP2":98, - "K_NP3":99,"K_NP4":100,"K_NP5":101,"K_NP6":102, - "K_NP7":103,"K_NP8":104,"K_NP9":105,"K_NPSTAR":106, - "K_NPPLUS":107,"K_SEPARATOR":108,"K_NPMINUS":109,"K_NPDOT":110, - "K_NPSLASH":111,"K_F1":112,"K_F2":113,"K_F3":114,"K_F4":115, - "K_F5":116,"K_F6":117,"K_F7":118,"K_F8":119,"K_F9":120, - "K_F10":121,"K_F11":122,"K_F12":123,"K_NUMLOCK":144,"K_SCROLL":145, - "K_LSHIFT":160,"K_RSHIFT":161,"K_LCONTROL":162,"K_RCONTROL":163, - "K_LALT":164,"K_RALT":165, - "K_COLON":186,"K_EQUAL":187,"K_COMMA":188,"K_HYPHEN":189, - "K_PERIOD":190,"K_SLASH":191,"K_BKQUOTE":192, - "K_LBRKT":219,"K_BKSLASH":220,"K_RBRKT":221, - "K_QUOTE":222,"K_oE2":226,"K_OE2":226, - "K_LOPT":50001,"K_ROPT":50002, - "K_NUMERALS":50003,"K_SYMBOLS":50004,"K_CURRENCIES":50005, - "K_UPPER":50006,"K_LOWER":50007,"K_ALPHA":50008, - "K_SHIFTED":50009,"K_ALTGR":50010, - "K_TABBACK":50011,"K_TABFWD":50012 + ...USVirtualKeyCodes, } as {[name: string]: number}, codesUS: [ @@ -117,34 +94,34 @@ const Codes = { getModifierState(layerId: string): number { var modifier=0; if(layerId.indexOf('shift') >= 0) { - modifier |= Codes.modifierCodes['SHIFT']; + modifier |= ModifierKeyConstants.K_SHIFTFLAG; } // The chiral checks must not be directly exclusive due each other to visual OSK feedback. var ctrlMatched=false; if(layerId.indexOf('leftctrl') >= 0) { - modifier |= Codes.modifierCodes['LCTRL']; + modifier |= ModifierKeyConstants.LCTRLFLAG; ctrlMatched=true; } if(layerId.indexOf('rightctrl') >= 0) { - modifier |= Codes.modifierCodes['RCTRL']; + modifier |= ModifierKeyConstants.RCTRLFLAG; ctrlMatched=true; } if(layerId.indexOf('ctrl') >= 0 && !ctrlMatched) { - modifier |= Codes.modifierCodes['CTRL']; + modifier |= ModifierKeyConstants.K_CTRLFLAG; } var altMatched=false; if(layerId.indexOf('leftalt') >= 0) { - modifier |= Codes.modifierCodes['LALT']; + modifier |= ModifierKeyConstants.LALTFLAG; altMatched=true; } if(layerId.indexOf('rightalt') >= 0) { - modifier |= Codes.modifierCodes['RALT']; + modifier |= ModifierKeyConstants.RALTFLAG; altMatched=true; } if(layerId.indexOf('alt') >= 0 && !altMatched) { - modifier |= Codes.modifierCodes['ALT']; + modifier |= ModifierKeyConstants.K_ALTFLAG; } return modifier; @@ -160,9 +137,9 @@ const Codes = { var modifier=0; if(layerId.indexOf('caps') >= 0) { - modifier |= Codes.modifierCodes['CAPS']; + modifier |= ModifierKeyConstants.CAPITALFLAG; } else { - modifier |= Codes.modifierCodes['NO_CAPS']; + modifier |= ModifierKeyConstants.NOTCAPITALFLAG; } return modifier; diff --git a/common/web/keyboard-processor/src/text/defaultRules.ts b/common/web/keyboard-processor/src/text/defaultRules.ts index 5ad708bd67a..931eb5200b2 100644 --- a/common/web/keyboard-processor/src/text/defaultRules.ts +++ b/common/web/keyboard-processor/src/text/defaultRules.ts @@ -2,6 +2,7 @@ // We should start splitting off code needed by keyboards even without a KeyboardProcessor active. // There's an upcoming `/common/web/types` package that 'codes' and 'keyboards' may fit well within. +import { ModifierKeyConstants} from '@keymanapp/common-types'; import Codes from "./codes.js"; import type KeyEvent from "./keyEvent.js"; import type OutputTarget from "./outputTarget.js"; @@ -190,7 +191,7 @@ export default class DefaultRules { // check if exact match to SHIFT's code. Only the 'default' and 'shift' layers should have default key outputs. // TODO: Extend to allow AltGr as well - better mnemonic support. - if(keyShiftState == Codes.modifierCodes['SHIFT']) { + if(keyShiftState == ModifierKeyConstants.K_SHIFTFLAG) { keyShiftState = 1; } else if(keyShiftState != 0) { if(ruleBehavior) { diff --git a/common/web/keyboard-processor/src/text/kbdInterface.ts b/common/web/keyboard-processor/src/text/kbdInterface.ts index b9e12b91386..438d328f0dc 100644 --- a/common/web/keyboard-processor/src/text/kbdInterface.ts +++ b/common/web/keyboard-processor/src/text/kbdInterface.ts @@ -6,6 +6,7 @@ //#region Imports import { type DeviceSpec } from "@keymanapp/web-utils"; +import { ModifierKeyConstants } from '@keymanapp/common-types'; import Codes from "./codes.js"; import type KeyEvent from "./keyEvent.js"; @@ -552,8 +553,8 @@ export default class KeyboardInterface extends KeyboardHarness { * @returns */ private static matchModifiersToRuleChirality(eventModifiers: number, targetModifierMask: number): number { - const CHIRAL_ALT = Codes.modifierCodes["LALT"] | Codes.modifierCodes["RALT"]; - const CHIRAL_CTRL = Codes.modifierCodes["LCTRL"] | Codes.modifierCodes["RCTRL"]; + const CHIRAL_ALT = ModifierKeyConstants.LALTFLAG | ModifierKeyConstants.RALTFLAG; + const CHIRAL_CTRL = ModifierKeyConstants.LCTRLFLAG | ModifierKeyConstants.RCTRLFLAG; let modifiers = eventModifiers; @@ -563,7 +564,7 @@ export default class KeyboardInterface extends KeyboardHarness { if(altIntersection) { // Undo the chiral part and replace with non-chiral. - modifiers ^= altIntersection | Codes.modifierCodes["ALT"]; + modifiers ^= altIntersection | ModifierKeyConstants.K_ALTFLAG; } } @@ -573,7 +574,7 @@ export default class KeyboardInterface extends KeyboardHarness { if(ctrlIntersection) { // Undo the chiral part and replace with non-chiral. - modifiers ^= ctrlIntersection | Codes.modifierCodes["CTRL"]; + modifiers ^= ctrlIntersection | ModifierKeyConstants.K_CTRLFLAG; } } @@ -939,7 +940,7 @@ export default class KeyboardInterface extends KeyboardHarness { // Denote the changed store as part of the matched rule's behavior. this.ruleBehavior.setStore[systemId] = strValue; return true; - } + } return false; } @@ -1178,4 +1179,4 @@ export default class KeyboardInterface extends KeyboardHarness { (function() { // This will be the only call within the keyboard-processor module. KeyboardInterface.__publishShorthandAPI(); -}()); \ No newline at end of file +}()); diff --git a/common/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/web/keyboard-processor/src/text/keyboardProcessor.ts index cd4be7bb6c0..836c9912a64 100644 --- a/common/web/keyboard-processor/src/text/keyboardProcessor.ts +++ b/common/web/keyboard-processor/src/text/keyboardProcessor.ts @@ -17,6 +17,7 @@ import KeyboardInterface, { SystemStoreIDs, VariableStore } from "./kbdInterface import RuleBehavior from "./ruleBehavior.js"; import { DeviceSpec, globalObject } from "@keymanapp/web-utils"; +import { ModifierKeyConstants } from '@keymanapp/common-types'; // #endregion @@ -275,7 +276,8 @@ export default class KeyboardProcessor extends EventEmitter { let keyShiftState=0; const lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'] as const; - const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const; + const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const; + const lockModifiers = [ ModifierKeyConstants.CAPITALFLAG, ModifierKeyConstants.NUMLOCKFLAG, ModifierKeyConstants.SCROLLFLAG] as const; if(!this.activeKeyboard) { return true; @@ -289,14 +291,14 @@ export default class KeyboardProcessor extends EventEmitter { if(this.activeKeyboard.isChiral && (this.activeKeyboard.emulatesAltGr) && (this.modStateFlags & Codes.modifierBitmasks['ALT_GR_SIM']) == Codes.modifierBitmasks['ALT_GR_SIM']) { keyShiftState |= Codes.modifierBitmasks['ALT_GR_SIM']; - keyShiftState &= ~Codes.modifierCodes['RALT']; + keyShiftState &= ~ModifierKeyConstants.RALTFLAG; } // Set stateKeys where corresponding value is passed in e.Lstates let stateMutation = false; for(let i=0; i < lockNames.length; i++) { if(e.Lstates & Codes.stateBitmasks[lockNames[i]]) { - this.stateKeys[lockKeys[i]] = !!(e.Lstates & Codes.modifierCodes[lockNames[i]]); + this.stateKeys[lockKeys[i]] = !!(e.Lstates & lockModifiers[i]); stateMutation = true; } } @@ -314,7 +316,7 @@ export default class KeyboardProcessor extends EventEmitter { if(!e || !e.isModifier) { // Mnemonic keystrokes manipulate the SHIFT property based on CAPS state. // We need to unflip them when tracking the OSK layer. - keyShiftState ^= Codes.modifierCodes['SHIFT']; + keyShiftState ^= ModifierKeyConstants.K_SHIFTFLAG; } } @@ -323,23 +325,22 @@ export default class KeyboardProcessor extends EventEmitter { } private updateStates(): void { - var lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'] as const; - var lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const; + const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const; + const lockModifiers = [ModifierKeyConstants.CAPITALFLAG, ModifierKeyConstants.NUMLOCKFLAG, ModifierKeyConstants.SCROLLFLAG] as const; + const noLockModifers = [ModifierKeyConstants.NOTCAPITALFLAG, ModifierKeyConstants.NOTNUMLOCKFLAG, ModifierKeyConstants.NOTSCROLLFLAG] as const; for(let i=0; i < lockKeys.length; i++) { const key = lockKeys[i]; const flag = this.stateKeys[key]; - const onBit = lockNames[i]; - const offBit = 'NO_' + lockNames[i]; // Ensures that the current mod-state info properly matches the currently-simulated // state key states. if(flag) { - this.modStateFlags |= Codes.modifierCodes[onBit]; - this.modStateFlags &= ~Codes.modifierCodes[offBit]; + this.modStateFlags |= lockModifiers[i]; + this.modStateFlags &= ~noLockModifers[i]; } else { - this.modStateFlags &= ~Codes.modifierCodes[onBit]; - this.modStateFlags |= Codes.modifierCodes[offBit]; + this.modStateFlags &= ~lockModifiers[i]; + this.modStateFlags |= noLockModifers[i]; } } } @@ -484,25 +485,25 @@ export default class KeyboardProcessor extends EventEmitter { // Toggle the modifier represented by our input argument. switch(id) { case 'shift': - modifier ^= Codes.modifierCodes['SHIFT']; + modifier ^= ModifierKeyConstants.K_SHIFTFLAG; break; case 'leftctrl': - modifier ^= Codes.modifierCodes['LCTRL']; + modifier ^= ModifierKeyConstants.LCTRLFLAG; break; case 'rightctrl': - modifier ^= Codes.modifierCodes['RCTRL']; + modifier ^= ModifierKeyConstants.RCTRLFLAG; break; case 'ctrl': - modifier ^= Codes.modifierCodes['CTRL']; + modifier ^= ModifierKeyConstants.K_CTRLFLAG; break; case 'leftalt': - modifier ^= Codes.modifierCodes['LALT']; + modifier ^= ModifierKeyConstants.LALTFLAG; break; case 'rightalt': - modifier ^= Codes.modifierCodes['RALT']; + modifier ^= ModifierKeyConstants.RALTFLAG; break; case 'alt': - modifier ^= Codes.modifierCodes['ALT']; + modifier ^= ModifierKeyConstants.K_ALTFLAG; break; default: s = id; diff --git a/common/web/keyboard-processor/tests/node/chirality.js b/common/web/keyboard-processor/tests/node/chirality.js index 9df87c6eda2..70dca3d47fd 100644 --- a/common/web/keyboard-processor/tests/node/chirality.js +++ b/common/web/keyboard-processor/tests/node/chirality.js @@ -4,9 +4,10 @@ import fs from 'fs'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); -import { Codes, KeyboardInterface, MinimalKeymanGlobal } from '@keymanapp/keyboard-processor'; +import { KeyboardInterface, MinimalKeymanGlobal } from '@keymanapp/keyboard-processor'; import { NodeKeyboardLoader } from '@keymanapp/keyboard-processor/node-keyboard-loader'; import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core'; +import { ModifierKeyConstants } from '@keymanapp/common-types'; describe('Engine - Chirality', function() { let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/chirality.json')); @@ -53,14 +54,14 @@ describe('Engine - Chirality', function() { } describe("Chiral modifier mapping", function() { - let VIRTUAL_KEY_CODE = Codes.modifierCodes["VIRTUAL_KEY"]; - let CTRL_CODE = Codes.modifierCodes["CTRL"]; - let LCTRL_CODE = Codes.modifierCodes["LCTRL"]; - let RCTRL_CODE = Codes.modifierCodes["RCTRL"]; - let ALT_CODE = Codes.modifierCodes["ALT"]; - let LALT_CODE = Codes.modifierCodes["LALT"]; - let RALT_CODE = Codes.modifierCodes["RALT"]; - let SHIFT_CODE = Codes.modifierCodes["SHIFT"]; + let VIRTUAL_KEY_CODE = ModifierKeyConstants.VIRTUAL_KEYFLAG; + let CTRL_CODE = ModifierKeyConstants.K_CTRLFLAG; + let LCTRL_CODE = ModifierKeyConstants.LCTRLFLAG; + let RCTRL_CODE = ModifierKeyConstants.RCTRLFLAG; + let ALT_CODE = ModifierKeyConstants.K_ALTFLAG; + let LALT_CODE = ModifierKeyConstants.LALTFLAG; + let RALT_CODE = ModifierKeyConstants.RALTFLAG; + let SHIFT_CODE = ModifierKeyConstants.K_SHIFTFLAG; it("does not affect non-chiral KeyEvents - CTRL only", function() { let initialModifiers = VIRTUAL_KEY_CODE | CTRL_CODE; @@ -249,4 +250,4 @@ describe('Engine - Chirality', function() { assert.equal(modifierTarget, mappedModifiers); }); }); -}); \ No newline at end of file +}); diff --git a/common/web/keyboard-processor/tests/node/non-positional-rules.js b/common/web/keyboard-processor/tests/node/non-positional-rules.js index 090df453c1e..aba54643aee 100644 --- a/common/web/keyboard-processor/tests/node/non-positional-rules.js +++ b/common/web/keyboard-processor/tests/node/non-positional-rules.js @@ -1,5 +1,5 @@ import { assert } from 'chai'; -import fs from 'fs'; +import { ModifierKeyConstants } from '@keymanapp/common-types'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); @@ -44,8 +44,8 @@ describe('Engine - rule processing', function() { let mnemonicEvent = new KeyEvent({ // sil_ipa is a mnenomic keyboard: it expects codes based on the key's standard character output. Lcode: '>'.charCodeAt(0), // 62 - Lmodifiers: Codes.modifierCodes.SHIFT, // '>' is shift-layer. - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lmodifiers: ModifierKeyConstants.K_SHIFTFLAG, // '>' is shift-layer. + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_N, @@ -66,7 +66,7 @@ describe('Engine - rule processing', function() { // sil_ipa is a mnenomic keyboard: it expects codes based on the key's standard character output. Lcode: '>'.charCodeAt(0), // 62 Lmodifiers: 0, // '>' is shift-layer, not default - and this matters for context matching. - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_N, @@ -84,8 +84,8 @@ describe('Engine - rule processing', function() { let positionalEvent = new KeyEvent({ // If it were positional, we'd use this instead: Lcode: Codes.keyCodes.K_COMMA, // 188 - Lmodifiers: Codes.modifierCodes.SHIFT, // '>' is shift-layer. - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lmodifiers: ModifierKeyConstants.K_SHIFTFLAG, // '>' is shift-layer. + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_N, @@ -123,7 +123,7 @@ describe('Engine - rule processing', function() { // armenian is a KMW 1.0 keyboard: it expects codes based on the key's standard character output. Lcode: 'a'.charCodeAt(0), Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NO_CAPSFLAG | ModifierKeyConstants.NO_NUM_LOCKFLAG | ModifierKeyConstants.NO_SCROLL_LOCKFLAG, LisVirtualKey: false, kName: '', vkCode: Codes.keyCodes.K_N, @@ -143,7 +143,7 @@ describe('Engine - rule processing', function() { // armenian is a KMW 1.0 keyboard: it expects codes based on the key's standard character output. Lcode: 'a'.charCodeAt(0), Lmodifiers: 27, - Lstates: Codes.modifierCodes.CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.SCROLL_LOCK | 0x5C00, + Lstates: ModifierKeyConstants.CAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.SCROLLFLAG | 0x5C00, LisVirtualKey: false, kName: '', vkCode: Codes.keyCodes.K_N, @@ -163,7 +163,7 @@ describe('Engine - rule processing', function() { // armenian is a KMW 1.0 keyboard: it expects codes based on the key's standard character output. Lcode: 'a'.charCodeAt(0), Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_N, @@ -182,7 +182,7 @@ describe('Engine - rule processing', function() { // If it were positional, we'd use this instead: Lcode: Codes.keyCodes.K_A, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_N, @@ -195,4 +195,4 @@ describe('Engine - rule processing', function() { assert.isTrue(positionalResult.triggerKeyDefault); }); }); -}); \ No newline at end of file +}); diff --git a/common/web/keyboard-processor/tests/node/specialized-backspace.js b/common/web/keyboard-processor/tests/node/specialized-backspace.js index 4c12e6e742e..db2be071e8f 100644 --- a/common/web/keyboard-processor/tests/node/specialized-backspace.js +++ b/common/web/keyboard-processor/tests/node/specialized-backspace.js @@ -6,6 +6,7 @@ const require = createRequire(import.meta.url); import { Codes, KeyboardInterface, KeyboardProcessor, KeyEvent, MinimalKeymanGlobal, Mock } from '@keymanapp/keyboard-processor'; import { NodeKeyboardLoader } from '@keymanapp/keyboard-processor/node-keyboard-loader'; +import { ModifierKeyConstants } from '@keymanapp/common-types'; const TEST_DEVICE = { @@ -17,8 +18,6 @@ const TEST_DEVICE = { // Basic scaffolding necessary to use special, locally-defined test keyboards. const COMMON_KBD_SCRIPT_PROPS = new (function (){ - var modCodes = Codes.modifierCodes; - this.KMINVER="10.0"; // this.KV left empty - we aren't doing layout stuff for this test, so it's "fine". // - also this.KV.KLS @@ -26,7 +25,7 @@ const COMMON_KBD_SCRIPT_PROPS = new (function (){ this.KH=''; this.KM=0; this.KBVER="0.0.1"; - this.KMBM=modCodes.SHIFT /* 0x0010 */; + this.KMBM=ModifierKeyConstants.K_SHIFTFLAG /* 0x0010 */; this.gs=function(t,e) { return this.g_main(t,e); }; @@ -131,7 +130,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -159,7 +158,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_A, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_A, @@ -194,7 +193,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -229,7 +228,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -257,7 +256,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -285,7 +284,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -320,7 +319,7 @@ describe('Engine - specialized backspace handling', function() { let event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, - Lstates: Codes.modifierCodes.NO_CAPS | Codes.modifierCodes.NO_NUM_LOCK | Codes.modifierCodes.NO_SCROLL_LOCK, + Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, @@ -346,4 +345,4 @@ describe('Engine - specialized backspace handling', function() { assert.equal(transform.deleteLeft, 0); assert.isNotOk(transform.deleteRight); }); -}); \ No newline at end of file +}); diff --git a/common/web/types/src/consts/modifier-key-constants.ts b/common/web/types/src/consts/modifier-key-constants.ts new file mode 100644 index 00000000000..245cbf70f37 --- /dev/null +++ b/common/web/types/src/consts/modifier-key-constants.ts @@ -0,0 +1,33 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Modifier key bit-flags + */ + +export const ModifierKeyConstants = { + // Define Keyman Developer modifier bit-flags (exposed for use by other modules) + // Compare against /common/include/kmx_file.h. CTRL+F "#define LCTRLFLAG" to find the secton. + LCTRLFLAG: 0x0001, // Left Control flag + RCTRLFLAG: 0x0002, // Right Control flag + LALTFLAG: 0x0004, // Left Alt flag + RALTFLAG: 0x0008, // Right Alt flag + K_SHIFTFLAG: 0x0010, // Either shift flag + K_CTRLFLAG: 0x0020, // Either ctrl flag + K_ALTFLAG: 0x0040, // Either alt flag + K_METAFLAG: 0x0080, // Either Meta-key flag (tentative). Not usable in keyboard rules; + // Used internally (currently, only by KMW) to ensure Meta-key + // shortcuts safely bypass rules + // Meta key = Command key on macOS, Windows key on Windows/Linux + CAPITALFLAG: 0x0100, // Caps lock on + NOTCAPITALFLAG: 0x0200, // Caps lock NOT on + NUMLOCKFLAG: 0x0400, // Num lock on + NOTNUMLOCKFLAG: 0x0800, // Num lock NOT on + SCROLLFLAG: 0x1000, // Scroll lock on + NOTSCROLLFLAG: 0x2000, // Scroll lock NOT on + ISVIRTUALKEY: 0x4000, // It is a Virtual Key Sequence + VIRTUALCHARKEY: 0x8000, // Keyman 6.0: Virtual Key Cap Sequence NOT YET + + // Note: OTHER_MODIFIER = 0x10000, used by KMX+ for the + // other modifier flag in layers, > 16 bit so not available here. + // See keys_mod_other in keyman_core_ldml.ts +} diff --git a/common/web/types/src/consts/virtual-key-constants.ts b/common/web/types/src/consts/virtual-key-constants.ts index 3347660f015..7b083241bdc 100644 --- a/common/web/types/src/consts/virtual-key-constants.ts +++ b/common/web/types/src/consts/virtual-key-constants.ts @@ -1,6 +1,5 @@ // Define standard keycode numbers (exposed for use by other modules) -// TODO-LDML: merge with common\web\keyboard-processor\src\text\codes.ts /** * May include non-US virtual key codes @@ -128,7 +127,7 @@ export const USVirtualKeyCodes = { 'k_?C1':193, K_oDF:0xDF, K_ODF:0xDF, - /*K_LOPT:50001, + K_LOPT:50001, K_ROPT:50002, K_NUMERALS:50003, K_SYMBOLS:50004, @@ -139,7 +138,7 @@ export const USVirtualKeyCodes = { K_SHIFTED:50009, K_ALTGR:50010, K_TABBACK:50011, - K_TABFWD:50012*/ + K_TABFWD:50012 }; const k = USVirtualKeyCodes; diff --git a/common/web/types/src/kmx/kmx.ts b/common/web/types/src/kmx/kmx.ts index 35c0c61c3d4..4f53e29fde1 100644 --- a/common/web/types/src/kmx/kmx.ts +++ b/common/web/types/src/kmx/kmx.ts @@ -1,4 +1,5 @@ import * as r from 'restructure'; +import { ModifierKeyConstants } from '../consts/modifier-key-constants.js'; /* Definitions from kmx_file.h. Must be kept in sync */ @@ -343,25 +344,25 @@ export class KMXFile { public static readonly HK_CTRL = 0x00020000; public static readonly HK_SHIFT = 0x00040000; - public static readonly LCTRLFLAG = 0x0001; // Left Control flag - public static readonly RCTRLFLAG = 0x0002; // Right Control flag - public static readonly LALTFLAG = 0x0004; // Left Alt flag - public static readonly RALTFLAG = 0x0008; // Right Alt flag - public static readonly K_SHIFTFLAG = 0x0010; // Either shift flag - public static readonly K_CTRLFLAG = 0x0020; // Either ctrl flag - public static readonly K_ALTFLAG = 0x0040; // Either alt flag + public static readonly LCTRLFLAG = ModifierKeyConstants.LCTRLFLAG; // Left Control flag + public static readonly RCTRLFLAG = ModifierKeyConstants.RCTRLFLAG; // Right Control flag + public static readonly LALTFLAG = ModifierKeyConstants.LALTFLAG; // Left Alt flag + public static readonly RALTFLAG = ModifierKeyConstants.RALTFLAG; // Right Alt flag + public static readonly K_SHIFTFLAG = ModifierKeyConstants.K_SHIFTFLAG; // Either shift flag + public static readonly K_CTRLFLAG = ModifierKeyConstants.K_CTRLFLAG; // Either ctrl flag + public static readonly K_ALTFLAG = ModifierKeyConstants.K_ALTFLAG; // Either alt flag //public static readonly K_METAFLAG = 0x0080; // Either Meta-key flag (tentative). Not usable in keyboard rules; // Used internally (currently, only by KMW) to ensure Meta-key // shortcuts safely bypass rules // Meta key = Command key on macOS, Windows key on Windows - public static readonly CAPITALFLAG = 0x0100; // Caps lock on - public static readonly NOTCAPITALFLAG = 0x0200; // Caps lock NOT on - public static readonly NUMLOCKFLAG = 0x0400; // Num lock on - public static readonly NOTNUMLOCKFLAG = 0x0800; // Num lock NOT on - public static readonly SCROLLFLAG = 0x1000; // Scroll lock on - public static readonly NOTSCROLLFLAG = 0x2000; // Scroll lock NOT on - public static readonly ISVIRTUALKEY = 0x4000; // It is a Virtual Key Sequence - public static readonly VIRTUALCHARKEY = 0x8000; // Keyman 6.0: Virtual Key Cap Sequence NOT YET + public static readonly CAPITALFLAG = ModifierKeyConstants.CAPITALFLAG; // Caps lock on + public static readonly NOTCAPITALFLAG = ModifierKeyConstants.NOTCAPITALFLAG; // Caps lock NOT on + public static readonly NUMLOCKFLAG = ModifierKeyConstants.NUMLOCKFLAG; // Num lock on + public static readonly NOTNUMLOCKFLAG = ModifierKeyConstants.NOTNUMLOCKFLAG; // Num lock NOT on + public static readonly SCROLLFLAG = ModifierKeyConstants.SCROLLFLAG; // Scroll lock on + public static readonly NOTSCROLLFLAG = ModifierKeyConstants.NOTSCROLLFLAG; // Scroll lock NOT on + public static readonly ISVIRTUALKEY = ModifierKeyConstants.ISVIRTUALKEY; // It is a Virtual Key Sequence + public static readonly VIRTUALCHARKEY = ModifierKeyConstants.VIRTUALCHARKEY; // Keyman 6.0: Virtual Key Cap Sequence NOT YET // Note: OTHER_MODIFIER = 0x10000, used by KMX+ for the // other modifier flag in layers, > 16 bit so not available here. diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 0ddee928c29..2e0ede953f4 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -19,7 +19,9 @@ export { UnicodeSetParser, UnicodeSet } from './ldml-keyboard/unicodeset-parser- export { VariableParser, MarkerParser } from './ldml-keyboard/pattern-parser.js'; export { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from './ldml-keyboard/ldml-keyboard-xml-reader.js'; +export { USVirtualKeyCodes } from './consts/virtual-key-constants.js'; export * as Constants from './consts/virtual-key-constants.js'; +export { ModifierKeyConstants } from './consts/modifier-key-constants.js'; export { defaultCompilerOptions, CompilerBaseOptions, CompilerCallbacks, CompilerOptions, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerCallbackOptions, @@ -58,4 +60,4 @@ export * as KeymanFileTypes from './util/file-types.js'; export * as Schemas from './schemas.js'; export * as SchemaValidators from './schema-validators.js'; -export * as xml2js from './deps/xml2js/xml2js.js'; \ No newline at end of file +export * as xml2js from './deps/xml2js/xml2js.js'; diff --git a/web/src/app/browser/src/defaultBrowserRules.ts b/web/src/app/browser/src/defaultBrowserRules.ts index cbd70fc8c77..1ac48016892 100644 --- a/web/src/app/browser/src/defaultBrowserRules.ts +++ b/web/src/app/browser/src/defaultBrowserRules.ts @@ -1,3 +1,4 @@ +import { ModifierKeyConstants } from '@keymanapp/common-types'; import { Codes, DefaultRules, @@ -45,7 +46,7 @@ export default class DefaultBrowserRules extends DefaultRules { // This method will be handled between `ContextManager` and PageContextAttachment: // pageContextAttachment.findNeighboringInput(contextManager.activeTarget.getElement(), ) case Codes.keyCodes['K_TAB']: - moveToNext((Lkc.Lmodifiers & Codes.modifierCodes['SHIFT']) != 0); + moveToNext((Lkc.Lmodifiers & ModifierKeyConstants.K_SHIFTFLAG) != 0); break; case Codes.keyCodes['K_TABBACK']: moveToNext(true); diff --git a/web/src/app/browser/src/hardwareEventKeyboard.ts b/web/src/app/browser/src/hardwareEventKeyboard.ts index 84fa62ed61f..29e867aa13c 100644 --- a/web/src/app/browser/src/hardwareEventKeyboard.ts +++ b/web/src/app/browser/src/hardwareEventKeyboard.ts @@ -1,4 +1,5 @@ import { Codes, DeviceSpec, KeyEvent, KeyMapping, Keyboard, KeyboardProcessor } from '@keymanapp/keyboard-processor'; +import { ModifierKeyConstants } from '@keymanapp/common-types'; import { HardKeyboard, processForMnemonicsAndLegacy } from 'keyman/engine/main'; import { DomEventTracker } from 'keyman/engine/events'; @@ -96,25 +97,24 @@ export function preprocessKeyboardEvent(e: KeyboardEvent, keyboardState: Keyboar curModState |= (e.getModifierState("Shift") ? 0x10 : 0); - let modifierCodes = Codes.modifierCodes; if(e.getModifierState("Control")) { curModState |= ((e.location != 0 && ctrlEvent) ? - (e.location == 1 ? modifierCodes['LCTRL'] : modifierCodes['RCTRL']) : // Condition 1 + (e.location == 1 ? ModifierKeyConstants.LCTRLFLAG : ModifierKeyConstants.RCTRLFLAG) : // Condition 1 prevModState & 0x0003); // Condition 2 } if(e.getModifierState("Alt")) { curModState |= ((e.location != 0 && altEvent) ? - (e.location == 1 ? modifierCodes['LALT'] : modifierCodes['RALT']) : // Condition 1 + (e.location == 1 ? ModifierKeyConstants.LALTFLAG : ModifierKeyConstants.RALTFLAG) : // Condition 1 prevModState & 0x000C); // Condition 2 } // Stage 2 - detect state key information. It can be looked up per keypress with no issue. let Lstates = 0; - Lstates |= e.getModifierState('CapsLock') ? modifierCodes['CAPS'] : modifierCodes['NO_CAPS']; - Lstates |= e.getModifierState('NumLock') ? modifierCodes['NUM_LOCK'] : modifierCodes['NO_NUM_LOCK']; + Lstates |= e.getModifierState('CapsLock') ? ModifierKeyConstants.CAPITALFLAG : ModifierKeyConstants.NOTCAPITALFLAG; + Lstates |= e.getModifierState('NumLock') ? ModifierKeyConstants.NUMLOCKFLAG : ModifierKeyConstants.NOTNUMLOCKFLAG; Lstates |= (e.getModifierState('ScrollLock')) - ? modifierCodes['SCROLL_LOCK'] : modifierCodes['NO_SCROLL_LOCK']; + ? ModifierKeyConstants.SCROLLFLAG : ModifierKeyConstants.NOTSCROLLFLAG; // We need these states to be tracked as well for proper OSK updates. curModState |= Lstates; @@ -128,14 +128,14 @@ export function preprocessKeyboardEvent(e: KeyboardEvent, keyboardState: Keyboar keyboardState.modStateFlags = curModState; // For European keyboards, not all browsers properly send both key-up events for the AltGr combo. - let altGrMask = modifierCodes['RALT'] | modifierCodes['LCTRL']; + let altGrMask = ModifierKeyConstants.RALTFLAG | ModifierKeyConstants.LCTRLFLAG; if((prevModState & altGrMask) == altGrMask && (curModState & altGrMask) != altGrMask) { // We just released AltGr - make sure it's all released. curModState &= ~ altGrMask; } // Perform basic filtering for Windows-based ALT_GR emulation on European keyboards. - if(curModState & modifierCodes['RALT']) { - curModState &= ~modifierCodes['LCTRL']; + if(curModState & ModifierKeyConstants.RALTFLAG) { + curModState &= ~ModifierKeyConstants.LCTRLFLAG; } let modifierBitmasks = Codes.modifierBitmasks; @@ -148,14 +148,14 @@ export function preprocessKeyboardEvent(e: KeyboardEvent, keyboardState: Keyboar // Note for future - embedding a kill switch here would facilitate disabling AltGr / Right-alt simulation. if(activeKeyboard.emulatesAltGr && (Lmodifiers & modifierBitmasks['ALT_GR_SIM']) == modifierBitmasks['ALT_GR_SIM']) { Lmodifiers ^= modifierBitmasks['ALT_GR_SIM']; - Lmodifiers |= modifierCodes['RALT']; + Lmodifiers |= ModifierKeyConstants.RALTFLAG; } } else { // No need to sim AltGr here; we don't need chiral ALTs. Lmodifiers = (curModState & 0x10) | // SHIFT - ((curModState & (modifierCodes['LCTRL'] | modifierCodes['RCTRL'])) ? 0x20 : 0) | - ((curModState & (modifierCodes['LALT'] | modifierCodes['RALT'])) ? 0x40 : 0); + ((curModState & (ModifierKeyConstants.LCTRLFLAG | ModifierKeyConstants.RCTRLFLAG)) ? 0x20 : 0) | + ((curModState & (ModifierKeyConstants.LALTFLAG | ModifierKeyConstants.RALTFLAG)) ? 0x40 : 0); } @@ -164,7 +164,7 @@ export function preprocessKeyboardEvent(e: KeyboardEvent, keyboardState: Keyboar * because some keyboards specify their own modifierBitmask, which won't include it. * We don't currently use that reference in this method, but that may change in the future. */ - Lmodifiers |= (e.metaKey ? modifierCodes['META']: 0); + Lmodifiers |= (e.metaKey ? ModifierKeyConstants.K_METAFLAG: 0); // Physically-typed keys require use of a 'desktop' form factor and thus are based on a virtual "physical" Device. diff --git a/web/src/engine/main/src/hardKeyboard.ts b/web/src/engine/main/src/hardKeyboard.ts index 5870bb707ca..a07904f4a6b 100644 --- a/web/src/engine/main/src/hardKeyboard.ts +++ b/web/src/engine/main/src/hardKeyboard.ts @@ -1,6 +1,7 @@ import { EventEmitter } from "eventemitter3"; import { Keyboard, KeyMapping, KeyEvent, type RuleBehavior, Codes } from "@keymanapp/keyboard-processor"; import { KeyEventSourceInterface } from 'keyman/engine/events'; +import { ModifierKeyConstants } from '@keymanapp/common-types'; interface EventMap { /** @@ -12,14 +13,12 @@ interface EventMap { export default class HardKeyboard extends EventEmitter implements KeyEventSourceInterface { } export function processForMnemonicsAndLegacy(s: KeyEvent, activeKeyboard: Keyboard, baseLayout: string): KeyEvent { - const modCodes = Codes.modifierCodes; - // Mnemonic handling. if(activeKeyboard && activeKeyboard.isMnemonic) { // The following will never set a code corresponding to a modifier key, so it's fine to do this, // which may change the value of Lcode, here. - s.setMnemonicCode(!!(s.Lmodifiers & modCodes.SHIFT), !!(s.Lmodifiers & modCodes.CAPS)); + s.setMnemonicCode(!!(s.Lmodifiers & ModifierKeyConstants.K_SHIFTFLAG), !!(s.Lmodifiers & ModifierKeyConstants.CAPITALFLAG)); } // Other minor physical-keyboard adjustments From 66c74e067a73b4467bda7520f4485290a4af9567 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 5 Aug 2024 15:51:03 +0200 Subject: [PATCH 2/2] refactor(web): don't include new `ModifierKeyConstants` in `modifierCodes` Keep `modifierCodes` as legacy API. This addresses a code review comment (https://github.com/keymanapp/keyman/pull/12072#discussion_r1703685759). --- common/web/keyboard-processor/src/text/codes.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/web/keyboard-processor/src/text/codes.ts b/common/web/keyboard-processor/src/text/codes.ts index 7f98b661891..c94d5b7152c 100644 --- a/common/web/keyboard-processor/src/text/codes.ts +++ b/common/web/keyboard-processor/src/text/codes.ts @@ -8,8 +8,6 @@ import { ModifierKeyConstants, USVirtualKeyCodes } from '@keymanapp/common-types const Codes = { modifierCodes: { - ...ModifierKeyConstants, - // Debug-mode keyboards compiled before Keyman 18.0 referenced the `ModifierKeyConstants` // constants via the names established below. We must continue to support them, as they're // essentially part of the keyboard API now.