Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
7f1bd71
feat(common): Establish epic/embed-osk-in-kmx branch 🔱
mcdurdin Sep 29, 2025
3be434a
refactor(windows): consolidate legacy_kmx_file.h into kmx_file.h
mcdurdin Sep 30, 2025
31c8f09
refactor(windows): consolidate mc_kmxfile.h
mcdurdin Sep 30, 2025
49846fe
feat(common): add KF_KMXPLUSOSK and VERSION_190 to kmx_file.h
mcdurdin Sep 30, 2025
c17ea67
docs(common): make KF_KMXPLUSOSK flag independent of KF_KMXPLUS
mcdurdin Oct 2, 2025
12cac0e
Merge branch 'epic/embed-osk-in-kmx' into chore/A19S13-merge-master-i…
keyman-server Oct 10, 2025
66d4c16
Merge pull request #14925 from keymanapp/chore/A19S13-merge-master-in…
keyman-server Oct 10, 2025
e4a2aa7
Merge pull request #14866 from keymanapp/refactor/windows/consolidate…
mcdurdin Oct 13, 2025
4d436e4
Update mcompile.h
mcdurdin Oct 13, 2025
9358dee
Merge pull request #14947 from keymanapp/refactor/windows/consolidate…
mcdurdin Oct 13, 2025
fd17bb5
Merge pull request #14869 from keymanapp/feat/common/kmx-plus-osk-fla…
mcdurdin Oct 13, 2025
9406e16
refactor(common): split KMX+ binary format from in-memory representation
mcdurdin Oct 15, 2025
db5aa51
change(developer): add unit test to verify special key cap definitions
mcdurdin Oct 16, 2025
1f8c6fb
Merge branch 'epic/embed-osk-in-kmx' into feat/common/add-osk-embed-s…
mcdurdin Oct 16, 2025
39951f1
Merge branch 'feat/common/add-osk-embed-support-to-kmx-plus' into cha…
mcdurdin Oct 16, 2025
b4bb07e
refactor(common): consolidate header struct to kmx-plus-file.ts
mcdurdin Oct 17, 2025
693c741
feat(common): add version header to KMX+ Typescript modules
mcdurdin Oct 17, 2025
57e0e69
refactor(core): add support for header.version to Core LDML
mcdurdin Oct 20, 2025
8d74d2c
feat(developer): add targetVersion support to kmc and kmc-kmn
mcdurdin Oct 21, 2025
d779274
test(core): add unit tests for v19.0 kmx+ format
mcdurdin Oct 22, 2025
77ea540
refactor(core): DRY out filling of sub-section data and fix cross-pla…
mcdurdin Oct 22, 2025
c114d84
Merge branch 'feat/core/add-kmx-plus-version-header' into feat/develo…
mcdurdin Oct 22, 2025
66258e6
Merge branch 'feat/developer/add-targetversion-parameter' into test/c…
mcdurdin Oct 22, 2025
6dd878d
test(developer): fix tests for versioning
mcdurdin Oct 22, 2025
d068ba4
test(developer): fix tests for versioning
mcdurdin Oct 22, 2025
069802b
Merge branch 'feat/developer/add-targetversion-parameter' into test/c…
mcdurdin Oct 22, 2025
f165453
docs(common): clarify usage of KMXPlus structures
mcdurdin Oct 22, 2025
d987f3f
chore(developer): clean up variable names and filenames
mcdurdin Oct 22, 2025
0362397
Merge pull request #14905 from keymanapp/feat/common/add-osk-embed-su…
mcdurdin Oct 22, 2025
c20949a
Merge pull request #14969 from keymanapp/change/developer/test-specia…
mcdurdin Oct 22, 2025
95a5bcc
Merge branch 'epic/embed-osk-in-kmx' into refactor/common/consolidate…
mcdurdin Oct 22, 2025
0227b27
Merge branch 'refactor/common/consolidate-kmx-plus-header-struct' int…
mcdurdin Oct 22, 2025
648cd2b
Merge branch 'feat/developer/add-kmx-plus-version-header' into feat/c…
mcdurdin Oct 22, 2025
e3fbe51
Merge branch 'feat/core/add-kmx-plus-version-header' into feat/develo…
mcdurdin Oct 22, 2025
00dd5b3
Merge branch 'feat/developer/add-targetversion-parameter' into test/c…
mcdurdin Oct 22, 2025
83b6247
Update common/web/types/src/kmx/kmx.ts
mcdurdin Oct 23, 2025
87420e1
Merge branch 'epic/embed-osk-in-kmx' into chore/A19S14-merge-master-i…
keyman-server Oct 24, 2025
35f189f
Merge pull request #15012 from keymanapp/chore/A19S14-merge-master-in…
keyman-server Oct 24, 2025
e970524
docs(core): add function comments
mcdurdin Oct 27, 2025
e6a3a31
Merge pull request #14990 from keymanapp/refactor/common/consolidate-…
mcdurdin Oct 28, 2025
b08f18e
Merge pull request #14991 from keymanapp/feat/developer/add-kmx-plus-…
mcdurdin Oct 28, 2025
268b87a
Merge pull request #14992 from keymanapp/feat/core/add-kmx-plus-versi…
mcdurdin Oct 29, 2025
f2d4dff
Merge pull request #14993 from keymanapp/feat/developer/add-targetver…
mcdurdin Oct 29, 2025
ee4cb5a
Merge pull request #14994 from keymanapp/test/core/add-unit-tests-for…
mcdurdin Oct 29, 2025
21c3a63
chore(windows): upgrade VC++ projects to v143 (VS2022)
mcdurdin Oct 30, 2025
3001346
Merge pull request #15073 from keymanapp/chore/epic/embed-osk-in-kmx/…
mcdurdin Oct 31, 2025
b7c93d9
Merge branch 'epic/embed-osk-in-kmx' into auto/A19S15-merge-master-in…
keyman-server Nov 7, 2025
256d1ae
Merge pull request #15117 from keymanapp/auto/A19S15-merge-master-int…
keyman-server Nov 7, 2025
fc0ff90
refactor(developer): rename layr.lists to layr.forms
mcdurdin Nov 12, 2025
34e71c4
Apply suggestions from code review
mcdurdin Nov 13, 2025
3b6e5ac
Merge pull request #15142 from keymanapp/refactor/developer-core/rena…
mcdurdin Nov 13, 2025
a53a159
feat(common): add v19 sections to KMX+ in Core and Developer
mcdurdin Nov 18, 2025
2076cd9
Merge branch 'epic/embed-osk-in-kmx' into feat/common/kmx-plus-osk-em…
mcdurdin Nov 18, 2025
ede398c
chore(developer): rename lists to forms
mcdurdin Nov 18, 2025
fa90df7
chore(common): Merge branch 'feat/common/kmx-plus-osk-embed-support'
mcdurdin Nov 18, 2025
4932790
feat(developer): reserve space for KMX+ header in KMX written from km…
mcdurdin Nov 18, 2025
f118036
refactor(developer): pass extra data from kmcmplib and move helpers f…
mcdurdin Nov 20, 2025
7ad056b
Merge branch 'epic/embed-osk-in-kmx' into auto/A19S16-merge-master-in…
keyman-server Nov 20, 2025
eabcc31
Merge pull request #15201 from keymanapp/auto/A19S16-merge-master-int…
keyman-server Nov 20, 2025
45496aa
Merge branch 'epic/embed-osk-in-kmx' into feat/common/kmx-plus-osk-em…
mcdurdin Nov 20, 2025
3e1c8ed
Merge branch 'feat/common/kmx-plus-osk-embed-support' into feat/devel…
mcdurdin Nov 20, 2025
76a4980
Merge branch 'feat/developer/reserve-space-for-kmxplus' into refactor…
mcdurdin Nov 20, 2025
75847a3
Apply suggestions from code review
mcdurdin Nov 21, 2025
d033c63
Update developer/src/kmc-kmn/test/embed-osk.tests.ts
mcdurdin Nov 21, 2025
8cfeace
Merge pull request #14976 from keymanapp/feat/common/kmx-plus-osk-emb…
mcdurdin Nov 21, 2025
770b6e3
Merge pull request #15183 from keymanapp/feat/developer/reserve-space…
mcdurdin Nov 21, 2025
cecc518
Update common/web/types/src/consts/modifier-key-constants.ts
mcdurdin Nov 21, 2025
0090d62
Merge branch 'epic/embed-osk-in-kmx' into refactor/developer/groundwo…
mcdurdin Nov 21, 2025
d7dd506
Merge pull request #15196 from keymanapp/refactor/developer/groundwor…
mcdurdin Nov 24, 2025
c546bf3
feat(developer): inject KMX+ into .kmx
mcdurdin Nov 24, 2025
12b77a5
feat(developer): convert .kvk into KMX+ and embed into .kmx
mcdurdin Nov 25, 2025
2751b53
Apply suggestions from code review
mcdurdin Nov 26, 2025
f50934b
chore(core): update keyman_core_ldml.h
mcdurdin Nov 27, 2025
ce5a5bb
refactor(developer): move KVK embed into embed-osk-kvk.ts
mcdurdin Nov 27, 2025
56cdf42
feat(developer): make shared constants tree-shakable
mcdurdin Nov 28, 2025
f3bab43
chore(developer): Apply suggestions from code review
mcdurdin Dec 1, 2025
00b5137
Merge pull request #15225 from keymanapp/feat/developer/embed-osk/inj…
mcdurdin Dec 1, 2025
99409ab
Merge pull request #15229 from keymanapp/feat/developer/embed-osk/con…
mcdurdin Dec 1, 2025
2d29ef5
Merge branch 'epic/embed-osk-in-kmx' into auto/A19S17-merge-master-in…
keyman-server Dec 5, 2025
2565c74
Merge pull request #15299 from keymanapp/auto/A19S17-merge-master-int…
keyman-server Dec 5, 2025
414092a
Merge branch 'epic/embed-osk-in-kmx' into auto/A19S20-merge-master-in…
mcdurdin Jan 16, 2026
6532bef
Merge pull request #15450 from keymanapp/auto/A19S20-merge-master-int…
mcdurdin Jan 16, 2026
7243112
Merge branch 'epic/embed-osk-in-kmx' into auto/A19S21-merge-master-in…
keyman-server Jan 31, 2026
55cb591
Merge pull request #15529 from keymanapp/auto/A19S21-merge-master-int…
keyman-server Jan 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<CompilerWarningsAsErrors>True</CompilerWarningsAsErrors>
<CheckFilenameConventions>True</CheckFilenameConventions>
<SkipMetadataFiles>True</SkipMetadataFiles>
<ProjectType>lexicalmodel</ProjectType>
<ProjectType>keyboard</ProjectType>
</Options>
</KeymanDeveloperProject>
45 changes: 30 additions & 15 deletions common/include/kmx_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#pragma once

#include <km_types.h>
#include "km_types.h"

#ifdef KM_CORE_LIBRARY
// TODO: move this to a common namespace keyman::common::kmx_file or similar in the future
Expand Down Expand Up @@ -52,8 +52,10 @@ namespace kmx {
#define VERSION_160 0x00001000
#define VERSION_170 0x00001100

#define VERSION_190 0x00001300

#define VERSION_MIN VERSION_50
#define VERSION_MAX VERSION_170
#define VERSION_MAX VERSION_190

//
// Backspace types
Expand All @@ -62,6 +64,9 @@ namespace kmx {
#define BK_DEFAULT 0
#define BK_DEADKEY 1

// Next character to delete is a Unicode surrogate pair
#define BK_SURROGATE 4

// Different begin types
#define BEGIN_ANSI 0
#define BEGIN_UNICODE 1
Expand Down Expand Up @@ -267,14 +272,24 @@ namespace kmx {
#define C_CODE_IFSYSTEMSTORE(store, val1, val2) U_UC_SENTINEL U_CODE_IFSYSTEMSTORE store val1 val2
#define C_CODE_SETSYSTEMSTORE(store, val) U_UC_SENTINEL U_CODE_SETSYSTEMSTORE store val

//
// COMP_KEYBOARD.dwFlags bitfield
//

#define KF_SHIFTFREESCAPS 0x0001
#define KF_CAPSONONLY 0x0002
#define KF_CAPSALWAYSOFF 0x0004
#define KF_LOGICALLAYOUT 0x0008
#define KF_AUTOMATICVERSION 0x0010

// 16.0: Support for LDML Keyboards in KMXPlus file format
#define KF_KMXPLUS 0x0020
/** 16.0+: A `COMP_KEYBOARD_KMXPLUSINFO` structure is present immediately after `COMP_KEYBOARD` */
#define KF_KMXPLUS 0x0020

/**
* 19.0+: The `COMP_KEYBOARD_KMXPLUSINFO` structure contains a v19 embedded OSK;
* may be used with or without KF_KMXPLUS.
*/
#define KF_KMXPLUSOSK 0x0040

#define HK_ALT 0x00010000
#define HK_CTRL 0x00020000
Expand Down Expand Up @@ -362,17 +377,17 @@ struct COMP_KEYBOARD_KMXPLUSINFO {
};

/**
* Only valid if comp_keyboard.dwFlags&KF_KMXPLUS
* Only valid if comp_keyboard.dwFlags&(KF_KMXPLUS|KF_KMXPLUSOSK)
*/
struct COMP_KEYBOARD_EX {
COMP_KEYBOARD header; // 0000 see COMP_KEYBOARD
COMP_KEYBOARD_KMXPLUSINFO kmxplus; // 0040 see COMP_KEYBOARD_EXTRA
struct COMP_KEYBOARD header; // 0000 see COMP_KEYBOARD
struct COMP_KEYBOARD_KMXPLUSINFO kmxplus; // 0040 see COMP_KEYBOARD_EXTRA
};

typedef COMP_KEYBOARD *PCOMP_KEYBOARD;
typedef COMP_STORE *PCOMP_STORE;
typedef COMP_KEY *PCOMP_KEY;
typedef COMP_GROUP *PCOMP_GROUP;
typedef struct COMP_KEYBOARD *PCOMP_KEYBOARD;
typedef struct COMP_STORE *PCOMP_STORE;
typedef struct COMP_KEY *PCOMP_KEY;
typedef struct COMP_GROUP *PCOMP_GROUP;

extern const int CODE__SIZE[];
#define CODE__SIZE_MAX 5
Expand All @@ -382,10 +397,10 @@ extern const int CODE__SIZE[];
#define KEYBOARDFILEGROUP_SIZE 24
#define KEYBOARDFILEKEY_SIZE 20

static_assert(sizeof(COMP_STORE) == KEYBOARDFILESTORE_SIZE, "COMP_STORE must be KEYBOARDFILESTORE_SIZE bytes");
static_assert(sizeof(COMP_KEY) == KEYBOARDFILEKEY_SIZE, "COMP_KEY must be KEYBOARDFILEKEY_SIZE bytes");
static_assert(sizeof(COMP_GROUP) == KEYBOARDFILEGROUP_SIZE, "COMP_GROUP must be KEYBOARDFILEGROUP_SIZE bytes");
static_assert(sizeof(COMP_KEYBOARD) == KEYBOARDFILEHEADER_SIZE, "COMP_KEYBOARD must be KEYBOARDFILEHEADER_SIZE bytes");
static_assert(sizeof(struct COMP_STORE) == KEYBOARDFILESTORE_SIZE, "COMP_STORE must be KEYBOARDFILESTORE_SIZE bytes");
static_assert(sizeof(struct COMP_KEY) == KEYBOARDFILEKEY_SIZE, "COMP_KEY must be KEYBOARDFILEKEY_SIZE bytes");
static_assert(sizeof(struct COMP_GROUP) == KEYBOARDFILEGROUP_SIZE, "COMP_GROUP must be KEYBOARDFILEGROUP_SIZE bytes");
static_assert(sizeof(struct COMP_KEYBOARD) == KEYBOARDFILEHEADER_SIZE, "COMP_KEYBOARD must be KEYBOARDFILEHEADER_SIZE bytes");

#ifdef KM_CORE_LIBRARY
} // namespace kmx
Expand Down
1 change: 1 addition & 0 deletions common/test/keyboards/embed_osk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
12 changes: 12 additions & 0 deletions common/test/keyboards/embed_osk/embed_osk.kpj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<KeymanDeveloperProject>
<Options>
<BuildPath>$PROJECTPATH\build</BuildPath>
<SourcePath>$PROJECTPATH\source</SourcePath>
<CompilerWarningsAsErrors>True</CompilerWarningsAsErrors>
<WarnDeprecatedCode>True</WarnDeprecatedCode>
<CheckFilenameConventions>False</CheckFilenameConventions>
<ProjectType>keyboard</ProjectType>
<Version>2.0</Version>
</Options>
</KeymanDeveloperProject>
33 changes: 33 additions & 0 deletions common/test/keyboards/embed_osk/source/embed_osk.kps
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>19.0.0.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Options>
<FollowKeyboardVersion/>
</Options>
<Info>
<Version/>
<Name>test_v19_kmxplus</Name>
<Description>test_v19_kmxplus</Description>
</Info>
<Files>
<File>
<Name>..\build\test_v19_kmxplus.kmx</Name>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>test_v19_kmxplus</Name>
<ID>test_v19_kmxplus</ID>
<Version>1.0</Version>
<Languages>
<Language ID="en">English</Language>
</Languages>
</Keyboard>
</Keyboards>
<Strings/>
</Package>
7 changes: 7 additions & 0 deletions common/test/keyboards/embed_osk/source/test_v19_kmxplus.kmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
store(&VERSION) '19.0'
store(&NAME) 'Test KMX+ space reserved in header'
store(&TARGETS) 'desktop'

begin Unicode > use(main)

group(main) using keys
162 changes: 160 additions & 2 deletions common/web/types/src/consts/modifier-key-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
* Modifier key bit-flags
*/

import { VisualKeyboardShiftState } from "../kvk/visual-keyboard.js";

/**
* This type is declared as a `const` rather than as an `enum` for
* historical reasons. Use `ModifierKeyConstant` instead where possible.
*/
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.
// 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 section.
LCTRLFLAG: 0x0001, // Left Control flag
RCTRLFLAG: 0x0002, // Right Control flag
LALTFLAG: 0x0004, // Left Alt flag
Expand All @@ -30,4 +37,155 @@ export const ModifierKeyConstants = {
// 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
};

/**
* Defines the standard modifier key flags used by Keyman. Note that some keys
* are chiral, and toggle key state is ignored if neither the __FLAG nor the
* corresponding NOT__FLAG are set.
*/
export enum ModifierKeyConstant {
NO_MODIFIER = 0,
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
};

export const LDML_MODIFIER_TO_KVK_MODIFIER = /* @__PURE__ */ (() => {
const m = new Map<ModifierKeyConstant, VisualKeyboardShiftState>();
m.set(ModifierKeyConstants.LCTRLFLAG, VisualKeyboardShiftState.KVKS_LCTRL);
m.set(ModifierKeyConstants.RCTRLFLAG, VisualKeyboardShiftState.KVKS_RCTRL);
m.set(ModifierKeyConstants.LALTFLAG, VisualKeyboardShiftState.KVKS_LALT);
m.set(ModifierKeyConstants.RALTFLAG, VisualKeyboardShiftState.KVKS_RALT);
m.set(ModifierKeyConstants.K_SHIFTFLAG, VisualKeyboardShiftState.KVKS_SHIFT);
m.set(ModifierKeyConstants.K_CTRLFLAG, VisualKeyboardShiftState.KVKS_CTRL);
m.set(ModifierKeyConstants.K_ALTFLAG, VisualKeyboardShiftState.KVKS_ALT);
return m;
})();

export const KVK_MODIFIER_TO_LDML_MODIFIER = /* @__PURE__ */ (() => {
const m = new Map<VisualKeyboardShiftState, ModifierKeyConstant>();
m.set(VisualKeyboardShiftState.KVKS_LCTRL, ModifierKeyConstants.LCTRLFLAG);
m.set(VisualKeyboardShiftState.KVKS_RCTRL, ModifierKeyConstants.RCTRLFLAG);
m.set(VisualKeyboardShiftState.KVKS_LALT, ModifierKeyConstants.LALTFLAG);
m.set(VisualKeyboardShiftState.KVKS_RALT, ModifierKeyConstants.RALTFLAG);
m.set(VisualKeyboardShiftState.KVKS_SHIFT, ModifierKeyConstants.K_SHIFTFLAG);
m.set(VisualKeyboardShiftState.KVKS_CTRL, ModifierKeyConstants.K_CTRLFLAG);
m.set(VisualKeyboardShiftState.KVKS_ALT, ModifierKeyConstants.K_ALTFLAG);
return m;
})();

export function translateLdmlModifiersToVisualKeyboardShift(modifiers: ModifierKeyConstant): VisualKeyboardShiftState {
if(modifiers == ModifierKeyConstant.NO_MODIFIER) {
return VisualKeyboardShiftState.KVKS_NORMAL;
}

if(modifiers &
(ModifierKeyConstant.CAPITALFLAG | ModifierKeyConstant.NUMLOCKFLAG | ModifierKeyConstant.SCROLLFLAG)
) {
// Caps/Num/Scroll are not supported in .kvk, in combination or alone
return null;
}

let shift: VisualKeyboardShiftState = 0;

for(const mod of LDML_MODIFIER_TO_KVK_MODIFIER.keys()) {
if(modifiers & mod) {
shift |= LDML_MODIFIER_TO_KVK_MODIFIER.get(mod);
}
}

return shift;
}

export function translateVisualKeyboardShiftToLdmlModifiers(shift: VisualKeyboardShiftState): ModifierKeyConstant {
if(shift == VisualKeyboardShiftState.KVKS_NORMAL) {
return 0;
}

let mod = 0;
for(const state of KVK_MODIFIER_TO_LDML_MODIFIER.keys()) {
if(shift & state) {
mod |= KVK_MODIFIER_TO_LDML_MODIFIER.get(state);
}
}

return mod;
}



function VkShiftStateToKmxShiftState(ShiftState: number): number {

interface TVKToKMX {
VK: VisualKeyboardShiftState; KMX: ModifierKeyConstant;
}

const Map: TVKToKMX[] = [
{VK: VisualKeyboardShiftState.KVKS_SHIFT, KMX: ModifierKeyConstant.K_SHIFTFLAG},
{VK: VisualKeyboardShiftState.KVKS_CTRL, KMX: ModifierKeyConstant.K_CTRLFLAG},
{VK: VisualKeyboardShiftState.KVKS_ALT, KMX: ModifierKeyConstant.K_ALTFLAG},
{VK: VisualKeyboardShiftState.KVKS_LCTRL, KMX: ModifierKeyConstant.LCTRLFLAG},
{VK: VisualKeyboardShiftState.KVKS_RCTRL, KMX: ModifierKeyConstant.RCTRLFLAG},
{VK: VisualKeyboardShiftState.KVKS_LALT, KMX: ModifierKeyConstant.LALTFLAG},
{VK: VisualKeyboardShiftState.KVKS_RALT, KMX: ModifierKeyConstant.RALTFLAG}
];

let result = 0;
for(let i = 0; i < Map.length; i++) {
if (ShiftState & Map[i].VK) {
result |= Map[i].KMX;
}
}

return result;
}

/**
* Convert a VK modifier combination bitmask to a hyphen-separated string of
* modifier names, e.g. for use in layer names and key identifiers. The name
* order matches the bit flag order from ModifierKeyConstant, not the bit flag
* order from VisualKeyboardShiftState, for historical reasons.
*/
export function visualKeyboardShiftToLayerName(shift: VisualKeyboardShiftState): string {

// index is ModifierKeyConstant, not VisualKeyboardShiftState
const modifierNames: string[] = [
'leftctrl',
'rightctrl',
'leftalt',
'rightalt',
'shift',
'ctrl',
'alt'
];

const mod = VkShiftStateToKmxShiftState(shift);
if(mod == 0) {
return 'default';
}

let result = '';
for(let i = 0; i < modifierNames.length; i++) {
if(mod & (1 << i)) {
result += modifierNames[i] + '-';
}
}
return result.substring(0, result.length - 1);
}
30 changes: 26 additions & 4 deletions common/web/types/src/consts/virtual-key-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,8 @@ export const USVirtualKeyCodes = {
K_TABFWD:50012
};

const k = USVirtualKeyCodes;

/** Map a CLDR scancode to a US VKey ala USVirtualKeyCodes */
export const CLDRScanToUSVirtualKeyCodes = {
export const CLDRScanToUSVirtualKeyCodes = /* @__PURE__ */ ((k) => ({
0x02: k.K_1,
0x03: k.K_2,
0x04: k.K_3,
Expand Down Expand Up @@ -202,7 +200,7 @@ export const CLDRScanToUSVirtualKeyCodes = {
0x73: k.K_oC1,
0x7D: k.K_oE2, // << Same as 0x56; found on jis

};
}))(USVirtualKeyCodes);

export type KeyMap = number[][];

Expand Down Expand Up @@ -230,3 +228,27 @@ export function CLDRScanToVkey(scan: number, badScans?: Set<number>): number {
}
}

const USVirtualKeyCodeNames = new Map<number, string>();

function fillVirtualKeyNames() {
Object.keys(USVirtualKeyCodes).forEach(name => {
USVirtualKeyCodeNames.set((<any>USVirtualKeyCodes)[name], name);
});

// These three keys have multiple definitions
USVirtualKeyCodeNames.set(USVirtualKeyCodes.K_oE2, 'K_oE2');
USVirtualKeyCodeNames.set(USVirtualKeyCodes.K_oC1, 'K_oC1');
USVirtualKeyCodeNames.set(USVirtualKeyCodes.K_oDF, 'K_oDF');
}

/**
* Get the defined name of a virtual key
* @param vk A defined Keyman virtual key
* @returns the name of the virtual key, or undefined if not found
*/
export function usVirtualKeyName(vk: number): string {
if(USVirtualKeyCodeNames.size == 0) {
fillVirtualKeyNames();
}
return USVirtualKeyCodeNames.get(vk);
}
Loading