Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(developer): rewrite ldml visual keyboard compiler #12402

Merged

Conversation

mcdurdin
Copy link
Member

@mcdurdin mcdurdin commented Sep 11, 2024

The visual keyboard compiler was never finished in 17.0. This rewrites it to:

  1. Use the kmxplus data rather than reading from xml directly
  2. Fill in visualkeyboard.header.kbdname
  3. Support modifiers
  4. Handle encoded characters like \u{1234}
  5. Handle string variables like ${one} (see TODO below)

Additional unit tests have been added to verify the behavior of the visual keyboard compiler in more detail.

TODO-LDML: string variables appear to have a secondary bug -- they seem to be returning the string 'undefined'. I have disabled the related tests and will examine this separately, and enable those tests once fixed. See #12403.

TODO-LDML: we should probably add a compiler warning + unit test for <layers formId="us"><layer id="base">, because this pattern does not make sense: when using non-touch forms, the <layer> element should use modifiers attribute, and correspondingly, modifiers attribute should not be used when formId is touch. See #12423.

Other fixes:

  1. The LDML XML reader was relying on its input being a Node.js Buffer even though it was declared Uint8Array, as it implicitly used Buffer.toString() to do text conversion. (Buffer subclasses from Uint8Array). This breaks when using Uint8Array directly and means we had an implicit dependency on Node.js. See also chore(common): xml2js -> fast-xml-parser #12331.
  2. XML errors were not captured in the LDML XML reader. See also chore(common): xml2js -> fast-xml-parser #12331.
  3. The unused and unfinished touch-layout-compiler.ts and keymanweb-compiler.ts have been removed along with corresponding unit tests and fixtures. These are replaced by Core implementations; see epic: web-core 🎼 #12291.

Will be cherry-picked to stable-17.0 (probably together with resolution to string variable bug)

Fixes: #12395

User Testing

Preparation:

  1. Install Keyman Developer artifact from this PR.
  2. Open the release/i/imperial_aramaic keyboards project in Keyman Developer, compile it, and locate the resulting build/imperial_aramaic.kmp.

TEST_LDML_VISUAL_KEYBOARD_WINDOWS: Install the imperial_aramaic.kmp file into Keyman for Windows 17.0.329. Verify that the On Screen Keyboard displays Aramaic characters.

TEST_LDML_VISUAL_KEYBOARD_MAC: Install the imperial_aramaic.kmp file into Keyman for macOS 17.0.329. Verify that the On Screen Keyboard displays Aramaic characters.

TEST_LDML_VISUAL_KEYBOARD_LINUX: Install the imperial_aramaic.kmp file into Keyman for Linux 17.0.329. Verify that the On Screen Keyboard displays Aramaic characters.

The visual keyboard compiler was never finished in 17.0. This rewrites
it to:

1. Use the kmxplus data rather than reading from xml directly
2. Fill in `visualkeyboard.header.kbdname`
3. Support modifiers
4. Handle encoded characters like `\u{1234}`
5. Handle string variables like `${one}`*

Additional unit tests have been added to verify the behavior of the
visual keyboard compiler in more detail.

TODO-LDML: string variables appear to have a secondary bug -- they seem
to be returning the string 'undefined'. I have disabled the related
tests and will examine this separately, and enable those tests once
fixed.

TODO-LDML: we should probably add a compiler warning + unit test for
`<layers formId="us"><layer id="base">`, because this pattern does not
make sense: when using non-touch forms, the `<layer>` element should use
`modifiers` attribute, and correspondingly, `modifiers` attribute should
_not_ be used when `formId` is `touch`.

Other fixes:

1. The LDML XML reader was relying on its input being a Node.js `Buffer`
   even though it was declared `Uint8Array`, as it implicitly used
   `Buffer.toString()` to do text conversion. (`Buffer` subclasses from
   `Uint8Array`). This breaks when using `Uint8Array` directly and means
   we had an implicit dependency on Node.js. See also #12331.
2. XML errors were not captured in the LDML XML reader. See also #12331.
3. The unused and unfinished touch-layout-compiler.ts and
   keymanweb-compiler.ts have been removed along with corresponding unit
   tests and fixtures. These are replaced by Core implementations; see
   #12291.

Fixes: #12395
@keymanapp-test-bot keymanapp-test-bot bot added has-user-test user-test-required User tests have not been completed labels Sep 11, 2024
@keymanapp-test-bot
Copy link

keymanapp-test-bot bot commented Sep 11, 2024

User Test Results

Test specification and instructions

Test Artifacts

@@ -146,7 +153,7 @@ export class LdmlKeyboardCompiler implements KeymanCompiler {
const kmx_binary = builder.compile();

const vkcompiler = new LdmlKeyboardVisualKeyboardCompiler(this.callbacks);
const vk = vkcompiler.compile(source);
const vk = vkcompiler.compile(kmx.kmxplus, this.callbacks.path.basename(outputFilename, '.kmx'));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const vk = vkcompiler.compile(kmx.kmxplus, this.callbacks.path.basename(outputFilename, '.kmx'));
const vk = vkcompiler.compile(kmx.kmxplus, outputFilename.replace(/\.kmx$/, ''));

Matches pattern for setting outputFilename -- we could add a baseFilename variable instead...

Comment on lines -183 to -185
if(compilerTestCallbacks.messages.length > 0) {
console.log(compilerTestCallbacks.messages);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The messages are printed already in the afterEach() function.

@@ -23,7 +24,8 @@
</keys>

<layers formId="us" minDeviceWidth="123">
<layer id="base">
<!-- TODO-LDML: unit test for <layers formId="us" with <layer id="base" should be illegal -->
<layer modifiers="none">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the kmxplus data rather than reading from xml directly

Does this mean the test fixture should use basic.kmx?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No -- this is a separate e2e test for the entire ldml compiler.

mcdurdin added a commit that referenced this pull request Sep 12, 2024
The visual keyboard compiler was never finished in 17.0. This rewrites
it to:

1. Use the kmxplus data rather than reading from xml directly
2. Fill in `visualkeyboard.header.kbdname`
3. Support modifiers
4. Handle encoded characters like `\u{1234}`
5. Handle string variables like `${one}`*

Additional unit tests have been added to verify the behavior of the
visual keyboard compiler in more detail.

* String variable tests will be enabled in next commit (which is a
cherry-pick of #12404).

Other fixes:

1. The LDML XML reader was relying on its input being a Node.js `Buffer`
   even though it was declared `Uint8Array`, as it implicitly used
   `Buffer.toString()` to do text conversion. (`Buffer` subclasses from
   `Uint8Array`). This breaks when using `Uint8Array` directly and means
   we had an implicit dependency on Node.js. See also #12331.
2. XML errors were not captured in the LDML XML reader. See also #12331.
3. The unused and unfinished touch-layout-compiler.ts and
   keymanweb-compiler.ts have been removed along with corresponding unit
   tests and fixtures. These will be replaced by Core implementations;
   see #12291.

Fixes: #12395
Cherry-pick-of: #12402
Comment on lines +82 to +83
assert.equal(vk.keys[3].shift, VisualKeyboard.VisualKeyboardShiftState.KVKS_RCTRL | VisualKeyboard.VisualKeyboardShiftState.KVKS_RALT);
assert.equal(vk.keys[4].shift, VisualKeyboard.VisualKeyboardShiftState.KVKS_SHIFT | VisualKeyboard.VisualKeyboardShiftState.KVKS_RALT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so do these correspond to

<layer modifiers="ctrlR altR, shift altR"><row keys="x" /></layer>

and then

<layer modifiers="caps"><row keys="x" /></layer>

has a .shift = null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the OSK does not support Caps so we omit the Caps layer.

Copy link
Contributor

@darcywong00 darcywong00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Comment on lines +50 to +52
static ERROR_InvalidXml = SevError | 0x0008;
static Error_InvalidXml = (o:{e: any}) =>
m(this.ERROR_InvalidXml, `The XML file could not be read: ${(o.e ?? '').toString()}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your change definitely trumps mine, mine was a stopgap for getting this across the line 😁

Copy link
Member

@srl295 srl295 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!

@dinakaranr
Copy link

Test Results

I tested this issue with the attached "Keyman developer 18.0.107-alpha-test-12402" build on the Windows 10.
Open the imperial_aramaic.kps project file.
Compile the build and generate the keyboard build.
Copy the imperial_aramaic.kmp file and share it to Windows, MacOS, and Linux.
Here is my observation.

  • TEST_LDML_VISUAL_KEYBOARD_WINDOWS (Passed):
  1. Installed the Keyman 17.0.329 keyboard build.
  2. Installed the "imperial_aramaic.kmp" keyboard.
  3. Open the Notepad application.
  4. Open the OSK from the window tray icon.
  5. Select the imperial_aramaic keyboard.
  6. Enter some text in the notepad
  7. Verified the OSK shows the imperial_aramaic letters.
    It works well. Thank you.
  • TEST_LDML_VISUAL_KEYBOARD_MAC (Failed):
  1. Installed the Keyman 17.0.329 keyboard build.
  2. Installed the "imperial_aramaic.kmp" keyboard.
  3. Open the "TextEdit" application.
  4. Open the OSK from the toolbar.
  5. Select the imperial_aramaic keyboard.
  6. Enter some text in the "TextEdit"
  7. Verified the OSK does not show the imperial_aramaic letters.
    It seems to be a problem. Thank you.
  • TEST_LDML_VISUAL_KEYBOARD_LINUX (Passed):
  1. Installed the Keyman 17.0.329 keyboard build.
  2. Installed the "imperial_aramaic.kmp" keyboard.
  3. Open the "TextEditor" application.
  4. Open the OSK from the toolbar.
  5. Select the imperial_aramaic keyboard.
  6. Enter some text in the "TextEditor".
  7. Verified the OSK shows the imperial_aramaic letters.
    It works well. Thank you.

@mcdurdin
Copy link
Member Author

@dinakaranr thank you for that test. I have addressed an issue in the compiler, so can you please retest on the Mac? Make sure you rebuild the keyboard before copying to the Mac for testing. Thanks!

@keymanapp-test-bot retest TEST_LDML_VISUAL_KEYBOARD_MAC

@keymanapp-test-bot keymanapp-test-bot bot added user-test-required User tests have not been completed and removed user-test-failed labels Sep 16, 2024
mcdurdin added a commit that referenced this pull request Sep 16, 2024
@dinakaranr
Copy link

Thank you for fixing this issue.

Test Results

I tested this issue with the attached "Keyman developer 18.0.107-alpha-test-12402" build on Windows 10.
Open the imperial_aramaic.kps project file.
Compile and regenerate the keyboard build.
Copy the imperial_aramaic.kmp file and share it to Windows, MacOS, and Linux.
Here I am sharing my observation.

  • TEST_LDML_VISUAL_KEYBOARD_MAC (Passed):
  1. Installed the Keyman 17.0.329 keyboard build.
  2. Installed the "imperial_aramaic.kmp" keyboard.
  3. Open the "TextEdit" application.
  4. Open the OSK from the toolbar.
  5. Select the imperial_aramaic keyboard.
  6. Enter some text in the "TextEdit"
  7. Verified the OSK appeared and the imperial_aramaic letters displayed
    It works well. Thank you.

@keymanapp-test-bot keymanapp-test-bot bot removed the user-test-required User tests have not been completed label Sep 16, 2024
@mcdurdin mcdurdin merged commit 6b83589 into master Sep 16, 2024
6 checks passed
@mcdurdin mcdurdin deleted the fix/developer/12395-rewrite-ldml-visual-keyboard-compiler branch September 16, 2024 22:40
@keyman-server
Copy link
Collaborator

Changes in this pull request will be available for download in Keyman version 18.0.114-alpha

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

bug(developer): generation of KVK from LDML keyboard seems to be creating an invalid .kvk file
5 participants