diff --git a/.github/actions/build-binary-packages/action.yml b/.github/actions/build-binary-packages/action.yml index e764a26ac7..1483f58e5c 100644 --- a/.github/actions/build-binary-packages/action.yml +++ b/.github/actions/build-binary-packages/action.yml @@ -25,7 +25,7 @@ runs: using: 'composite' steps: - name: Download Artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: keyman-srcpkg path: artifacts/keyman-srcpkg @@ -49,7 +49,7 @@ runs: echo '```' >> $GITHUB_STEP_SUMMARY - name: Store binary packages - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: keyman-binarypkgs-${{ inputs.dist }}_${{ inputs.arch }} path: | diff --git a/.github/labeler.yml b/.github/labeler.yml index fc37bf64b7..2549340624 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -5,86 +5,173 @@ # common ones. The others are commented out. There is still some variance between # folder names and labels; consider this documentation of that ;-) -docs: docs/** +docs: +- changed-files: + - any-glob-to-any-file: 'docs/**' # # Add labels based on changed files using actions/labeler # android/: - - android/** - - resources/teamcity/includes/** - - resources/teamcity/android/** -android/app/: android/KMAPro/** -android/engine/: android/KMEA/** -android/samples/: android/Samples/** + - changed-files: + - any-glob-to-any-file: + - android/** + - resources/teamcity/includes/** + - resources/teamcity/android/** +android/app/: + - changed-files: + - any-glob-to-any-file: + - android/KMAPro/** +android/engine/: + - changed-files: + - any-glob-to-any-file: + - android/KMEA/** +android/samples/: + - changed-files: + - any-glob-to-any-file: + - android/Samples/** common/: - - common/** - - resources/teamcity/includes/** - - resources/teamcity/common/** -common/web/: common/web/** + - changed-files: + - any-glob-to-any-file: + - common/** + - resources/teamcity/includes/** + - resources/teamcity/common/** +common/web/: + - changed-files: + - any-glob-to-any-file: + - common/web/** core/: - - core/** - - resources/teamcity/includes/** - - resources/teamcity/core/** + - changed-files: + - any-glob-to-any-file: + - core/** + - resources/teamcity/includes/** + - resources/teamcity/core/** developer/: - - developer/** - - resources/teamcity/includes/** - - resources/teamcity/developer/** + - changed-files: + - any-glob-to-any-file: + - developer/** + - resources/teamcity/includes/** + - resources/teamcity/developer/** developer/compilers/: - - developer/src/kmc/** - - developer/src/kmcmplib/** - - developer/src/kmc-*/** + - changed-files: + - any-glob-to-any-file: + - developer/src/kmc/** + - developer/src/kmcmplib/** + - developer/src/kmc-*/** developer/ide/: - - developer/src/server/** - - developer/src/tike/** + - changed-files: + - any-glob-to-any-file: + - developer/src/server/** + - developer/src/tike/** ios/: - - ios/** - - resources/teamcity/includes/** - - resources/teamcity/ios/** -ios/app/: ios/keyman/** -ios/engine/: ios/engine/** -ios/samples/: ios/samples/** + - changed-files: + - any-glob-to-any-file: + - ios/** + - resources/teamcity/includes/** + - resources/teamcity/ios/** +ios/app/: + - changed-files: + - any-glob-to-any-file: + - ios/keyman/** +ios/engine/: + - changed-files: + - any-glob-to-any-file: + - ios/engine/** +ios/samples/: + - changed-files: + - any-glob-to-any-file: + - ios/samples/** linux/: - - linux/** - - resources/teamcity/includes/** - - resources/teamcity/linux/** -linux/config/: linux/keyman-config/** -linux/engine/: linux/ibus-keyman/** + - changed-files: + - any-glob-to-any-file: + - linux/** + - resources/teamcity/includes/** + - resources/teamcity/linux/** +linux/config/: + - changed-files: + - any-glob-to-any-file: + - linux/keyman-config/** +linux/engine/: + - changed-files: + - any-glob-to-any-file: + - linux/ibus-keyman/** mac/: - - mac/** - - resources/teamcity/includes/** - - resources/teamcity/mac/** + - changed-files: + - any-glob-to-any-file: + - mac/** + - resources/teamcity/includes/** + - resources/teamcity/mac/** # mac/config/: # mac/engine/: mac/** -oem/: oem/** -oem/fv/: oem/firstvoices/** -oem/fv/android/: oem/firstvoices/android/** -oem/fv/ios/: oem/firstvoices/ios/** -oem/fv/windows/: oem/firstvoices/windows/** +oem/: + - changed-files: + - any-glob-to-any-file: + - oem/** +oem/fv/: + - changed-files: + - any-glob-to-any-file: + - oem/firstvoices/** +oem/fv/android/: + - changed-files: + - any-glob-to-any-file: + - oem/firstvoices/android/** +oem/fv/ios/: + - changed-files: + - any-glob-to-any-file: + - oem/firstvoices/ios/** +oem/fv/windows/: + - changed-files: + - any-glob-to-any-file: + - oem/firstvoices/windows/** -resources/: resources/** +resources/: + - changed-files: + - any-glob-to-any-file: + - resources/** web/: - - web/** - - resources/teamcity/includes/** - - resources/teamcity/web/** + - changed-files: + - any-glob-to-any-file: + - web/** + - resources/teamcity/includes/** + - resources/teamcity/web/** # web/bookmarklet/ -web/engine/: web/source/** -web/ui/: web/source/kmwui* -web/samples/: web/samples/** -web/predictive-text/: web/src/engine/predictive-text/** +web/engine/: + - changed-files: + - any-glob-to-any-file: + - web/source/** +web/ui/: + - changed-files: + - any-glob-to-any-file: + - web/source/kmwui* +web/samples/: + - changed-files: + - any-glob-to-any-file: + - web/samples/** +web/predictive-text/: + - changed-files: + - any-glob-to-any-file: + - web/src/engine/predictive-text/** windows/: - - windows/** - - resources/teamcity/includes/** - - resources/teamcity/windows/** -windows/config/: windows/src/desktop/** -windows/engine/: windows/src/engine/** + - changed-files: + - any-glob-to-any-file: + - windows/** + - resources/teamcity/includes/** + - resources/teamcity/windows/** +windows/config/: + - changed-files: + - any-glob-to-any-file: + - windows/src/desktop/** +windows/engine/: + - changed-files: + - any-glob-to-any-file: + - windows/src/engine/** diff --git a/.github/workflows/api-verification.yml b/.github/workflows/api-verification.yml index af6bc682dc..56726817dc 100644 --- a/.github/workflows/api-verification.yml +++ b/.github/workflows/api-verification.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Restore artifacts - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: | artifacts @@ -55,7 +55,7 @@ jobs: - name: Checkout if: steps.environment_step.outputs.SKIP_API_CHECK != 'true' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ steps.environment_step.outputs.GIT_SHA }}' fetch-depth: 0 @@ -84,7 +84,7 @@ jobs: - name: Archive .symbols file if: steps.environment_step.outputs.SKIP_API_CHECK != 'true' && always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: libkeymancore.symbols path: ${{ github.workspace }}/keyman/linux/debian/tmp/DEBIAN/symbols diff --git a/.github/workflows/build-test-publish-docker.yml b/.github/workflows/build-test-publish-docker.yml index 3c85d4ff91..edb9ebb98f 100644 --- a/.github/workflows/build-test-publish-docker.yml +++ b/.github/workflows/build-test-publish-docker.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout repository id: checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Build Docker images id: build run: | @@ -67,7 +67,7 @@ jobs: steps: - name: Checkout repository id: checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Test Docker images id: test diff --git a/.github/workflows/core-arm64-windows-test.yml b/.github/workflows/core-arm64-windows-test.yml index 237e60d4ef..0eb4e8f8f6 100644 --- a/.github/workflows/core-arm64-windows-test.yml +++ b/.github/workflows/core-arm64-windows-test.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ github.event.client_payload.buildSha }}' @@ -64,7 +64,7 @@ jobs: npm -v node -v - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' @@ -119,7 +119,7 @@ jobs: - name: Install meson shell: bash run: | - pip3 install --user meson + pip3 install --user meson==1.10.1 - name: Run test shell: bash diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 7503d51d21..d0c14de948 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: crowdin action uses: crowdin/github-action@v2.7.0 diff --git a/.github/workflows/deb-packaging.yml b/.github/workflows/deb-packaging.yml index 36bfd0d0ce..6e7fe54cb3 100644 --- a/.github/workflows/deb-packaging.yml +++ b/.github/workflows/deb-packaging.yml @@ -43,7 +43,7 @@ jobs: PRERELEASE_TAG: ${{ steps.prerelease_tag.outputs.PRERELEASE_TAG }} steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ github.event.client_payload.buildSha }}' @@ -121,7 +121,7 @@ jobs: echo "- $(find . -name keyman_\*.dsc)" >> $GITHUB_STEP_SUMMARY - name: Store source package - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: keyman-srcpkg path: | @@ -140,7 +140,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ github.event.client_payload.buildSha }}' sparse-checkout: '.github/actions/' @@ -166,7 +166,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ github.event.client_payload.buildSha }}' sparse-checkout: '.github/actions/' @@ -204,13 +204,13 @@ jobs: sudo rm -rf /usr/share/dotnet - name: Download Source Artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: keyman-srcpkg path: artifacts - name: Download Binary Artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: artifacts pattern: keyman-binarypkgs-* @@ -281,7 +281,7 @@ jobs: echo "::endgroup::" - name: Download Artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: keyman-signedpkgs @@ -343,7 +343,7 @@ jobs: steps: - name: Download Artifacts - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: artifacts pattern: keyman-* @@ -362,7 +362,7 @@ jobs: echo "SKIP_API_CHECK=${{ github.event.client_payload.skipApiCheck }}" >> artifacts/env - name: Cache artifacts - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: | artifacts diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 42d9f79363..ee7fe7d03d 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Update labels based on changed files - uses: actions/labeler@v4 + uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" - name: Update labels based on PR title diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index fc94cc688e..551045c056 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -50,7 +50,7 @@ jobs: fi - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: '${{ github.event.client_payload.buildSha }}' diff --git a/.github/workflows/pr-build-status.yml b/.github/workflows/pr-build-status.yml index 978a2b0995..bd5fe2f46a 100644 --- a/.github/workflows/pr-build-status.yml +++ b/.github/workflows/pr-build-status.yml @@ -1,40 +1,40 @@ # GENERATED FILE - DO NOT EDIT! -# -# Keyman is copyright (C) SIL Global. MIT License. -# -# Do not modify the script in .github/workflows/pr-build-status.yml directly; -# instead work on the sources in resources/build/pr-build-status and use the -# build.sh script to rebuild the .github/workflows/pr-build-status.yml file from -# them. -# -# build.sh will append the relevant portions of -# resources/build/pr-build-status/pr-build-status.mjs to the content in -# resources/build/pr-build-status/pr-build-status.prefix.yml to form the .github -# workflow file. -# -name: Keyman Build Summary -on: - status: - push: - branches-ignore: - - master - - beta - - stable-* - workflow_dispatch: - inputs: - commit: - description: 'Commit sha' - required: true - type: string -jobs: - run_pr_build_status: - name: Summarize build status checks - runs-on: ubuntu-latest - steps: - - name: Check PR build status - id: run_pr_build_status_script - uses: actions/github-script@v7 - with: +# +# Keyman is copyright (C) SIL Global. MIT License. +# +# Do not modify the script in .github/workflows/pr-build-status.yml directly; +# instead work on the sources in resources/build/pr-build-status and use the +# build.sh script to rebuild the .github/workflows/pr-build-status.yml file from +# them. +# +# build.sh will append the relevant portions of +# resources/build/pr-build-status/pr-build-status.mjs to the content in +# resources/build/pr-build-status/pr-build-status.prefix.yml to form the .github +# workflow file. +# +name: Keyman Build Summary +on: + status: + push: + branches-ignore: + - master + - beta + - stable-* + workflow_dispatch: + inputs: + commit: + description: 'Commit sha' + required: true + type: string +jobs: + run_pr_build_status: + name: Summarize build status checks + runs-on: ubuntu-latest + steps: + - name: Check PR build status + id: run_pr_build_status_script + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: script: | // This code is copied out of resources/build/pr-build-status/pr-build-status.mjs // where it is tested. It is copied inline here in order to avoid requiring the diff --git a/HISTORY.md b/HISTORY.md index 45405b8d55..0f0f3078da 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,36 @@ # Keyman Version History +## 19.0.220 alpha 2026-03-26 + +* fix(mac): improved adherence to backspace rules for compliant apps (#15561) + +## 19.0.219 alpha 2026-03-25 + +* maint(common): Update GitHub actions for Node 24 (#15762) +* fix(core): fix keydown/up handling for LDML keyboards (#15609) + +## 19.0.218 alpha 2026-03-24 + +* fix(developer): define globalThis for compiled custom lexical models (#15777) + +## 19.0.217 alpha 2026-03-17 + +* maint(mac): search for brew-installed rsync (#15765) + +## 19.0.216 alpha 2026-03-16 + +* docs: tweak walkthrough content (#15712) +* chore(deps): bump tar from 7.5.10 to 7.5.11 in /developer/src/server/src/win32/trayicon/addon-src (#15723) +* docs(linux): add documentation how input methods work in GTK (#15749) +* docs(core): improve keyhandling doc (#15736) +* maint(resources): try meson 1.10.1 (#15754) +* maint(ios): clean carthage before builds (#15757) + +## 19.0.215 alpha 2026-03-13 + +* chore(linux): fix dependency of Debian test suite (#15735) +* chore(linux): Update debian changelog (#15732) + ## 19.0.214 alpha 2026-03-12 * chore(linux): Update debian changelog (#15718) diff --git a/VERSION.md b/VERSION.md index 9daf8a196e..6659914f35 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -19.0.215 \ No newline at end of file +19.0.221 \ No newline at end of file diff --git a/core/docs/api/keyhandling.md b/core/docs/api/keyhandling.md index 6dcc3177b0..76576b56d8 100644 --- a/core/docs/api/keyhandling.md +++ b/core/docs/api/keyhandling.md @@ -1,42 +1,39 @@ # Key Handling -For each key press the processor will called twice, for the key down event -as well as for the key up event. Depending on the type of key pressed the -processor might handle the key itself or pass it on to the application. -The value of `emit_keystroke` in `km_core_actions` struct tells if the -processor handled the key (`emit_keystroke=0`) or not (`emit_keystroke=1`). -It is important that the same value gets set for both key down and key up -events, otherwise the application might miss some events which then looks -to the user like keys are stuck. +While Keyman Core does not generally emit actions from key up events, +the `emit_keystroke` value for a key up event will match the corresponding +key down event, in order to avoid 'stuck key' scenarios'. Usually the processor won't handle any frame keys and let the application deal with it. This allows shortcut keys like Ctrl+C -to work. The only exception is the Backspace key which is -handled internally if enough context is available. Regular keys will be -handled by the processor. +to work. One exception is the Backspace key which is +handled internally if enough context is available. Keyboards can define +rules for other frame keys, e.g. Ctrl+Key which are then +also handled internally. Regular keys will be handled by the processor. Note that there is a difference between CLDR/LDML and KMN keyboards if there are no rules/transforms defined for a key: KMN keyboards will output the cap value of the key (e.g. pressing a will output `a` if no rule is defined), whereas CLDR/LDML keyboards will suppress -any output for that key. +any output for that key. However, `km_core_actions.emit_keystroke` will +be `FALSE` for both KMN and CLR/LDML keyboards. The following table lists the state of `km_core_actions.emit_keystroke` on return of `km_core_process_event` when the following type of key is pressed: -|Type | KeyDown | KeyUp | -|-----------------------------|---------------|----------| -|Key with rule | FALSE | FALSE | -|Key w/o rule | FALSE | FALSE | -|Framekeys: | | | -|Enter | TRUE | TRUE | -|Backspace¹ | FALSE | FALSE | -|Backspace² | TRUE | TRUE | -|Ctrl+Key | TRUE | TRUE | -|Modifier key Shift| TRUE | TRUE | -|Modifier key Ctrl | TRUE | TRUE | -|Modifier key LAlt | TRUE | TRUE | +|Type | KeyDown/Up | +|-----------------------------|------------| +|Core key with rule | FALSE | +|Core key w/o rule | FALSE | +|Framekeys: | | +|Enter | TRUE | +|Backspace¹ | FALSE | +|Backspace² | TRUE | +|Ctrl+Key | TRUE | +|Modifier key Shift| TRUE | +|Modifier key Ctrl | TRUE | +|Modifier key LAlt | TRUE | 1: context available
2: without or with empty context diff --git a/core/src/km_core_processevent_api.cpp b/core/src/km_core_processevent_api.cpp index a2bca95ea8..ade2665353 100644 --- a/core/src/km_core_processevent_api.cpp +++ b/core/src/km_core_processevent_api.cpp @@ -50,6 +50,9 @@ km_core_process_event(km_core_state *state, if(state == nullptr) { return KM_CORE_STATUS_INVALID_ARGUMENT; } + if (vk == KM_CORE_VKEY_BKSP && is_key_down) { + state->set_backspace_handled_internally(false); + } km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags); if (state_should_invalidate_context(state, vk, modifier_state, is_key_down, event_flags)) { @@ -78,6 +81,10 @@ km_core_process_event(km_core_state *state, state->apply_actions_and_merge_app_context(); + if (vk == KM_CORE_VKEY_BKSP) { + state->set_backspace_handled_internally(!state->action_struct().emit_keystroke); + } + return status; } diff --git a/core/src/ldml/ldml_processor.cpp b/core/src/ldml/ldml_processor.cpp index 9ef36b62fc..e79a1f90be 100644 --- a/core/src/ldml/ldml_processor.cpp +++ b/core/src/ldml/ldml_processor.cpp @@ -179,21 +179,13 @@ ldml_processor::process_event( ldml_state.clear(); try { - if (!is_key_down) { - process_key_up(ldml_state); + if (vk == KM_CORE_VKEY_BKSP) { + process_backspace(ldml_state); + } else if (is_key_down) { + process_key_down(ldml_state); } else { - switch (vk) { - // Currently, only one VK gets spoecial treatment. - // Special handling for backspace VK - case KM_CORE_VKEY_BKSP: - process_backspace(ldml_state); - break; - default: - // all other VKs - process_key_down(ldml_state); - } // end of switch - } // end of normal processing - + process_key_up(ldml_state); + } // all key-up and key-down events end up here. // commit the ldml state into the core state ldml_state.commit(); @@ -210,11 +202,31 @@ void ldml_processor::process_key_up(ldml_event_state &ldml_state) const { // TODO-LDML: Implement caps lock handling - ldml_state.clear(); + + // Look up the key + bool found = false; + const std::u16string key_str = keys.lookup(ldml_state.get_vk(), ldml_state.get_modifier_state(), found); + + if (!found) { + ldml_state.emit_passthrough_keystroke(); + } } void ldml_processor::process_backspace(ldml_event_state &ldml_state) const { + if (ldml_state.get_modifier_state() & K_MODIFIERFLAG) { + // we never process modifier+bksp + ldml_state.emit_passthrough_keystroke(); + return; + } + + if (!ldml_state.is_key_down()) { + if (!ldml_state.get_state()->backspace_handled_internally()) { + ldml_state.emit_passthrough_keystroke(); + } + return; + } + if (!!bksp_transforms) { // process with an empty string via the bksp transforms auto matchedContext = process_output(ldml_state, std::u32string(), bksp_transforms.get()); diff --git a/core/src/ldml/ldml_processor.hpp b/core/src/ldml/ldml_processor.hpp index b673a9275c..a10294cc32 100644 --- a/core/src/ldml/ldml_processor.hpp +++ b/core/src/ldml/ldml_processor.hpp @@ -176,6 +176,9 @@ public: * @return the number of context items consumed */ size_t context_to_string(std::u32string &str, bool include_markers = true); + km_core_state* get_state() const { return state; } + + uint8_t is_key_down() const { return _is_key_down; } private: km_core_virtual_key _vk; diff --git a/core/src/state.cpp b/core/src/state.cpp index c6142b3456..47f29d0a67 100644 --- a/core/src/state.cpp +++ b/core/src/state.cpp @@ -52,6 +52,7 @@ state::state(km::core::abstract_processor & ap, km_core_option_item const *env) env->key, env->value); } + _backspace_handled_internally = false; _imx_callback = nullptr; _imx_object = nullptr; memset(const_cast(&_action_struct), 0, sizeof(km_core_actions)); @@ -117,4 +118,4 @@ void state::apply_actions_and_merge_app_context() { } this->_action_struct.deleted_context = km::core::get_deleted_context(app_context_for_deletion, this->_action_struct.code_points_to_delete); -} \ No newline at end of file +} diff --git a/core/src/state.hpp b/core/src/state.hpp index 49eea8ffd2..0cf58fb614 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -130,6 +130,7 @@ protected: core::debug_items _debug_items; km_core_keyboard_imx_platform _imx_callback; void *_imx_object; + bool _backspace_handled_internally; public: state(core::abstract_processor & kb, km_core_option_item const *env); @@ -174,6 +175,22 @@ public: km_core_actions const &actions ); void apply_actions_and_merge_app_context(); + + /** + * This is used to track whether the backspace key was handled internally + * during the keydown event. This is needed so that we can return the same + * value from the keyup event as we did for the keydown event. + * + * Backspace is the only key that we sometimes handle internally (if we + * have enough context) and sometimes not. By the time we get the keyup + * event the context already got updated and so we have no way of knowing + * whether or not the keydown handled it internally. Therefore this + * flag exists. + * + * Only used when processing KM_CORE_VKEY_BKSP with LDML keyboards. + */ + void set_backspace_handled_internally(bool handled) { _backspace_handled_internally = handled; } + bool backspace_handled_internally() const { return _backspace_handled_internally; } }; } // namespace core } // namespace km diff --git a/core/tests/unit/km_core_process_event.tests.cpp b/core/tests/unit/km_core_process_event.tests.cpp new file mode 100644 index 0000000000..67b84760b3 --- /dev/null +++ b/core/tests/unit/km_core_process_event.tests.cpp @@ -0,0 +1,355 @@ +/* + * Keyman is copyright (C) SIL Global. MIT License. + */ +#include +#include "path.hpp" +#include "state.hpp" +#include "kmx/kmx_processevent.h" + +#include "emscripten_filesystem.h" +#include "kmnkbd/action_items.hpp" +#include "load_kmx_file.hpp" + +using namespace km::core::kmx; +km::core::path test_dir; + +km_core_option_item test_env_opts[] = {KM_CORE_OPTIONS_END}; + +#define KEY_DOWN TRUE +#define KEY_UP FALSE + +struct TestData { + const char* test_name; + + const char* keyboard_name; + km_core_virtual_key vkey; + uint16_t modifier_state; + + // Initial context + km_core_cu const* context; + + // Whether keydown handled the event. Only relevant for keyup tests. + bool keydown_handled; + + // Expected actions for keydown and keyup + std::initializer_list keydown_actions; + std::initializer_list keyup_actions; +}; + +std::string GenerateTestName(const testing::TestParamInfo& info) { + return info.param.test_name; +} + +class ProcessEventTests : public testing::TestWithParam { +protected: + km_core_keyboard* keyboard = nullptr; + km_core_state* state = nullptr; + KMX_ProcessEvent process_event; + + void Initialize(TestData const& data) { + km::core::path kmxfile = km::core::path(test_dir / data.keyboard_name); + auto blob = km::tests::load_kmx_file(kmxfile.native().c_str()); + + EXPECT_EQ(km_core_keyboard_load_from_blob(kmxfile.stem().c_str(), blob.data(), blob.size(), &this->keyboard), KM_CORE_STATUS_OK); + EXPECT_EQ(km_core_state_create(this->keyboard, test_env_opts, &this->state), KM_CORE_STATUS_OK); + EXPECT_TRUE(this->process_event.Load(blob.data(), blob.size())); + if (data.context) { + EXPECT_EQ(km_core_state_context_set_if_needed(this->state, data.context), KM_CORE_CONTEXT_STATUS_UPDATED); + } + ((km::core::state*)this->state)->set_backspace_handled_internally(data.keydown_handled); + } + + void TearDown() override { + if (this->state) { + km_core_state_dispose(this->state); + this->state = nullptr; + } + if (this->keyboard) { + km_core_keyboard_dispose(this->keyboard); + this->keyboard = nullptr; + } + } +}; + +void print_all_action_items(km_core_state const* state) { + size_t n = 0; + auto act = km_core_state_action_items(state, &n); + std::cout << "Action items:" << std::endl; + for (size_t i = 0; i < n; i++) { + print_action_item("", *act++); + } + std::cout << "---------------" << std::endl; +} + +TEST_P(ProcessEventTests, ReturnsExpectedActionsForKeyDown) { + auto data = GetParam(); + Initialize(data); + EXPECT_EQ(km_core_process_event(this->state, data.vkey, data.modifier_state, + KEY_DOWN, KM_CORE_EVENT_FLAG_DEFAULT), KM_CORE_STATUS_OK); + // print_all_action_items(this->state); + EXPECT_TRUE(action_items(this->state, data.keydown_actions)); +} + +TEST_P(ProcessEventTests, ReturnsExpectedActionsForKeyUp) { + auto data = GetParam(); + Initialize(data); + EXPECT_EQ(km_core_process_event(this->state, data.vkey, data.modifier_state, KEY_UP, KM_CORE_EVENT_FLAG_DEFAULT), KM_CORE_STATUS_OK); + // print_all_action_items(this->state); + EXPECT_TRUE(action_items(this->state, data.keyup_actions)); +} + +union backspace_union { + km_core_backspace_item backspace; + uint32_t value; +}; +// const backspace_union backspace_with_context = {{KM_CORE_BT_CHAR, 'x'}}; +const backspace_union backspace_no_context = {{KM_CORE_BT_CHAR, 0}}; + +const TestData values[] = { + //-------------------------------------------------------------------- + // KMN + // Key with rule + {"KMN_VKey_A", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_A, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'d'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + {"KMN_Ctrl_VKey_A", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_A, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Key without rule + {"KMN_VKey_X", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_X, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'x'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + {"KMN_Ctrl_VKey_X", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_X, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Frame key without rule + {"KMN_VKey_Enter", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_ENTER, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // // Backspace (with available context) + // // TODO: fix the implementation to make this test pass. Currently failing in KeyUp + // {"KMN_VKey_Backspace_Ctxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, u"x", true, + // { // KeyDown + // // Once we use C++ 20 we can use: + // //{KM_CORE_IT_BACK, { 0, }, {.backspace = {KM_CORE_BT_CHAR, 'x'}}}, + // {KM_CORE_IT_BACK, { 0, }, {backspace_with_context.value}}, + // {KM_CORE_IT_END} + // }, + // { // KeyUp + // {KM_CORE_IT_END} + // } + // }, + // Backspace (without context) + {"KMN_VKey_Backspace_NoCtxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (with context) + {"KMN_Ctrl_VKey_Backspace_Ctxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (no context) + {"KMN_Ctrl_VKey_Backspace_NoCtxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Modifier frame key + {"KMN_VKey_Shift", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_SHIFT, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + + //-------------------------------------------------------------------- + // LDML + // Key with rule + {"LDML_VKey_A", "ldml/keyboards/k_020_fr.kmx", KM_CORE_VKEY_A, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'q'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + {"LDML_Ctrl_VKey_A", "ldml/keyboards/k_020_fr.kmx", KM_CORE_VKEY_A, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Key without rule + {"LDML_VKey_X", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_X, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_END} // LDML: no output without rule + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + {"LDML_Ctrl_VKey_X", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_X, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} // LDML: no output without rule + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Frame key without rule + {"LDML_VKey_Enter", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_ENTER, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Backspace (with available context) + {"LDML_VKey_Backspace_Ctxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, u"x", true, + { // KeyDown + // Once we use C++ 20 we can use: + //{KM_CORE_IT_BACK, { 0, }, {.backspace = {KM_CORE_BT_CHAR, 0}}}, + {KM_CORE_IT_BACK, { 0, }, {backspace_no_context.value}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + // Backspace (without context) + {"LDML_VKey_Backspace_NoCtxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (with context) + {"LDML_Ctrl_VKey_Backspace_Ctxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (no context) + {"LDML_Ctrl_VKey_Backspace_NoCtxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Modifier frame key + {"LDML_VKey_Shift", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_SHIFT, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, +}; + +INSTANTIATE_TEST_SUITE_P(KMXProcessEvent, ProcessEventTests, testing::ValuesIn(values), GenerateTestName); + +// provide our own `main` so that we can get the path of the exe so that +// we have a well-defined location to find our test keyboards +int main(int argc, char** argv) { +#ifdef __EMSCRIPTEN__ + test_dir = get_wasm_file_path(km::core::path(argv[0]).parent()); +#else + test_dir = km::core::path(argv[0]).parent(); +#endif + std::cout << "test_dir=" << test_dir.c_str() << std::endl; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/core/tests/unit/meson.build b/core/tests/unit/meson.build index 0637ace96e..5456650372 100644 --- a/core/tests/unit/meson.build +++ b/core/tests/unit/meson.build @@ -48,6 +48,18 @@ kmcorekeyboardapitests = executable('km_core_keyboard_api.tests', test('km-core-keyboard-api-tests', kmcorekeyboardapitests) +# tests for km_core_process_event +km_core_process_event_tests_exe = executable( + 'km_core_process_event_tests', + ['km_core_process_event.tests.cpp', common_test_files], + include_directories: [inc, libsrc], + cpp_args: defns + warns, + link_args: [ links, extra_link_args ], + dependencies: [icu_uc, icu_i18n, gtest_dep, gmock_dep], + objects: lib.extract_all_objects(recursive: false), +) +test('km_core_process_event', km_core_process_event_tests_exe) + subdir('json') subdir('utftest') subdir('kmnkbd') diff --git a/developer/docs/help/context/keyboard-editor.md b/developer/docs/help/context/keyboard-editor.md index 8dbc6e04b5..433cce5c4f 100644 --- a/developer/docs/help/context/keyboard-editor.md +++ b/developer/docs/help/context/keyboard-editor.md @@ -209,24 +209,24 @@ Display 102nd Key (as on European keyboards) : European keyboards (ISO layout) have one extra key that is not on US keyboards (ANSI layout). This key is positioned to the right of the left shift key. Some other keyboards have additional keys; these are not shown on the - layout designer. - + layout designer. + If you have a European layout selected as your Windows layout, the 102nd key will always be visible in the designer; ensure you select this checkbox if you want the 102nd key to always be visible to end users of the layout, irrespective of - their selected base layout. - + their selected base layout. + When a European layout is selected as your Windows layout, the shape of the Enter key will also change to take two rows, and the backslash key will move down one row, but not - otherwise change in behaviour. + otherwise change in behaviour. Keyboard Editor - On-Screen tab with ISO layout *See the difference between the two layouts in Keyman Developer.* > [!NOTE] - > The "Display 102nd Key (as on European keyboards)" checkbox can be left unchecked. + > The "Display 102nd Key (as on European keyboards)" checkbox can be left unchecked. > To ensure compatibility, the extra key shouldn't be assigned since it won't be accessible on an ANSI physical keyboard. Auto-fill underlying layout @@ -270,20 +270,20 @@ Template... be lost. Therefore, selecting an appropriate template early in the development process is suggested. - - template-basic: has only a phone layout (4 rows of keys), with three layers: default (K_A through K_Z - plus some punctuation), shift (Shift K_A through Shift K_Z, plus some punctuation), numeric (K_0 through + - template-basic: has only a phone layout (4 rows of keys), with three layers: default (K_A through K_Z + plus some punctuation), shift (Shift K_A through Shift K_Z, plus some punctuation), numeric (K_0 through K_9 unshifted and shifted, plus other non-alphanumerice keys). - - template-latin: has both phone and tablet layouts (which are identical except for some key spacing, - each with 4 rows of keys), with four layers: default, shift, numeric, symbol. The first three layers - are similar to those of template-basic, with the addition of longpress keys for accented characters. + - template-latin: has both phone and tablet layouts (which are identical except for some key spacing, + each with 4 rows of keys), with four layers: default, shift, numeric, symbol. The first three layers + are similar to those of template-basic, with the addition of longpress keys for accented characters. The symbol layer has many symbols not usually seen on a physical keyboard. - - template-traditional: has both phone (4 rows of keys) and tablet (5 rows of keys) layouts. The phone - layout is similar to the template-basic layout. The tablet layout has eight layers: default, shift, ctrl, - shift-ctrl, alt, shift-alt, ctrl-alt, shift-ctrl-alt. The default layer has the keys from the default layer + - template-traditional: has both phone (4 rows of keys) and tablet (5 rows of keys) layouts. The phone + layout is similar to the template-basic layout. The tablet layout has eight layers: default, shift, ctrl, + shift-ctrl, alt, shift-alt, ctrl-alt, shift-ctrl-alt. The default layer has the keys from the default layer of the desktop layout, the shift layer has the keys from the shift layer of the desktop layout, and so on. - + Import from On Screen : If you have an existing On-Screen Keyboard for your keyboard layout, importing the design from the On-Screen Keyboard can reduce the @@ -413,7 +413,7 @@ ID - `U_####[_####]` is used as a shortcut for a key that will output those Unicode values, if no rule matches it. This is similar to the overloaded behaviour for `K_` ids. Thus `####` - must be valid Unicode characters. + must be valid Unicode characters. The square bracket characters `[` and `]` indicate an optional portion of the sequence and are not to be included in the shortcut. E.g. `U_0259` would generate a schwa if no rule matches. It is still valid to have a rule such @@ -479,7 +479,7 @@ file. This makes certain operations simpler, such as batched rearranging of keys, or using another text editor to make bulk changes. The Code view uses the standard [editor](editor). -The format of the layout file is described in [Creating a touch keyboard layout guide](../guides/develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty). +The format of the layout file is described in [.keyman-touch-layout file format](../reference/file-types/keyman-touch-layout). #### Long-press, Flicks, and Multitaps controls diff --git a/developer/docs/help/guides/__index.txt b/developer/docs/help/guides/__index.txt new file mode 100644 index 0000000000..57ea270e2f --- /dev/null +++ b/developer/docs/help/guides/__index.txt @@ -0,0 +1 @@ +-distribute \ No newline at end of file diff --git a/developer/docs/help/guides/develop/__index.txt b/developer/docs/help/guides/develop/__index.txt new file mode 100644 index 0000000000..e88328ff8a --- /dev/null +++ b/developer/docs/help/guides/develop/__index.txt @@ -0,0 +1,4 @@ +-creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty.md +-creating-a-touch-keyboard-layout-for-amharic.md +-tutorial +-touch-keyboard-tutorial diff --git a/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty.md b/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty.md index f33ea20c34..a895225331 100644 --- a/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty.md +++ b/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty.md @@ -1,756 +1,3 @@ --- -title: Creating a Touch Keyboard Layout Part 2 +redirect: . --- - -
- - -
- -This article will continue the guide to creating a touch keyboard layout. In -particular, we'll look in more detail at how keys are arranged, just what can be -specified for each key, and lastly, how this all looks in the JSON code used to -define the long press layout. - -## Key and Key Layer Organization - -There are two issues that are immediately apparent when considering key layout -on touch devices. - -First, on smaller touch devices, such as phones, if we try to display the same -arrangement of keys that is used for a typical desktop keyboard, the keys are so -small that it is difficult to reliably select the wanted key. If used in -'portrait' view, key widths are too narrow for our 'fat fingers': - -![](../../images/touch_amharic_keyboard_4.png) - -Or if in 'landscape' view, key heights are too small: - -![](../../images/touch_amharic_keyboard_5.png) - -The situation is improved markedly if we limit the number of keys per row to ten -and have no more than four key rows: - -![](../../images/touch_amharic_keyboard_6.png) - -and, in landscape view: - -![](../../images/touch_amharic_keyboard_7.png) - -So which keys can be eliminated, and which keys must be on the base (default) -layer? This brings us to the second point. When using phones and other touch -layout devices rather than desktop keyboards, text entry is most often -single-handed, which makes it best to avoid using the 'shift' layer for entering -normal text. Secondary keyboard layers will, of course, still be usually needed -for uppercase, numerals and symbols, but will be used much less frequently. - -Most desktop keyboards (for European languages, at least) are already laid out -with no more than ten letter (or digit) keys per row, with the remaining keys -being used for accented letters, punctuation and other non-letter input. So the -obvious choice is to move non-letter keys (and accented letters) either to a -secondary key layer, or to long press ('pop-up') keys. The GFF Amharic desktop -keyboard is fortunately also arranged with only ten letters per key row (other -keys being used for punctuation, etc.), as the many different characters in the -Amharic 'abugida' are generated by multi-letter sequences rather than being -displayed on separate keys. The Geez script does not have both upper-case and -lower-case forms, so those initial consonants that require use of the 'shift' -layer on the desktop keyboard have been added to the corresponding base-layer -key as long press keys: - -![](../../images/touch_amharic_keyboard_8.png) - -Arrangement of punctuation and other non-letter keys is more flexible as mobile -users are generally familiar with using long press keys or a secondary key layer -for finding and entering digits and special characters. However, some -punctuation characters are used so frequently that they need to be on the base -layer. For the GFF Amharic keyboard, the most frequently used punctuation -characters can be output from the base layer using standard or long press keys. -The Geez word space character, in particular, is so frequently used that it was -considered useful to add it to the bottom key, adjacent to the space bar, as is -sometimes done for other scripts, such as Japanese, on desktop (physical) -keyboards. - -## Arranging keys with the layout editor - -The Keyman Developer layout editor really makes it quite easy to try different -key layouts and choose what is best for your keyboard. The image below -highlights just how, for any selected key, using the clickable icons circled, a -key row can be added above (1) or below (2), a key added before (3) or after -(4), the selected key deleted (5), and how an array of long press keys -(sometimes called "subkeys") can be added (6). - -![](../../images/touch_amharic_keyboard_9.png) - -## Key properties - -For each visual key, the appearance and behaviour is determined by a number of -properties: - -### Key code - -Each key must be given an identifying key code which is unique to the key layer. -Key codes by and large correspond to the virtual key codes used when creating a -keyboard program for a desktop keyboard, and should start with `K_`, for keys -mapped to standard Keyman virtual key names, e.g. `K_HYPHEN`, and `T_` or `U_` -for user-defined names, e.g. `T_ZZZ`. If keyboard rules exist matching the key -code in context, then the output from the key will be determined by the -processing of those rules. It is usually best to include explicit rules to -manage the output from each key, but if no rules matching the key code are -included in the keyboard program, and the key code matches the pattern -`U_xxxx[_yyyy...]` (where `xxxx` and -`yyyy` are 4 to 6-digit hex strings), then the Unicode characters -`U+xxxx` and `U+yyyy` will be output. As of Keyman 15, you -can use more than one Unicode character value in the id (earlier versions -permitted only one). The key code is always required, and a default code will -usually be generated automatically by Keyman Developer. - -- `K_xxxx` is used for a standard Keyman Desktop key name, e.g. - `K_W`, `K_ENTER`. You cannot make up your own `K_xxxx` names. - Many of the `K_` ids have overloaded output behaviour, for instance, if no - rule is matched for `K_W`, Keyman will output 'w' when it is touched. The - standard key names are listed in [Virtual Keys and Virtual Character - Keys](/developer/language/guide/virtual-keys "Virtual Keys and Virtual -Character Keys"). Typically, you would use only the "common" virtual key - codes. - -- `T_xxxx` is used for any user defined names, e.g. `T_SCHWA`. If you wanted - to use it, `T_ENTER` would also be valid. If no rule matches it, the key - will have no output behaviour. - -- `U_####[_####]` is used as a shortcut for a key that will output those - Unicode values, if no rule matches it. This is similar to the overloaded - behaviour for `K_` ids. Thus `####` must be valid Unicode characters. - The square bracket characters `[` and `]` indicate an optional portion of the sequence - and are not to be included in the shortcut. E.g. - `U_0259` would generate a schwa if no rule matches. It is still valid to - have a rule such as `+ [U_0259] > ...` - -As noted above, some `K_xxxx` codes emit characters, if no rule is defined. -There are also some codes which have special functions: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdentifierMeaning
`K_ENTER`Submit a form, or add a new line (multi-line); the key action may vary depending on the situation.
`K_BKSP`Delete back a single character. This key, if held down, will repeat. It is the only key code which triggers - repeat behavior.
`K_LOPT`Open the language menu (aka Globe key).
`K_ROPT`Hide the on screen keyboard.
`K_TAB`, `K_TABBACK`, `K_TABFWD`Move to next or previous element in a form. Note that these key functions are normally - implemented outside the touch layout, so should not typically be used. `K_TAB` will go to previous - element if used with the `shift` modifier.
- -Any key can be used to switch keyboard layers (see -[`nextlayer`](#toc-nextlayer)), but the following layer-switching key codes have -been added for switching to some commonly used secondary layers. Note that these -keys have no specific meaning; you must still set the `nextlayer` property on -the key. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdentifierMeaning
`K_NUMERALS`Switch to a numeric layer
`K_SYMBOLS`Switch to a symbol layer
`K_CURRENCIES`Switch to a currency layer
`K_SHIFTED`Switch to a shift layer
`K_ALTGR`Switch to a right-alt layer (desktop compatibility)
- -### Key text - -The key text is simply the character (or characters) that you want to appear on -the key cap. This will usually be the same as the characters generated when the -key is touched, unless contextual rules are used to generate output according to -a multi-key sequence, as will be true for the GFF Amharic keyboard. Unicode -characters can be specified either as a string using a target font or using the -standard hex notation `\uxxxx`. This may be sometimes more convenient, for -example, for characters from an uninstalled font, or for diacritic characters -that do not render well alone. - -A number of special text labels are recognized as identifying special purpose -keys, such as Shift, Backspace, Enter, etc., for which icons are more -appropriately used than a text label. A special font including these icons is -included with Keyman and automatically embedded and used in any web page using -Keyman. The list of icons in the font will probably be extended in future, but -for now the following special labels are recognized: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Text StringKey CapKey Purpose
`*Shift*`Select Shift layer (inactive). Use on the Shift key to indicate that it switches to the shift layer.
`*Shifted*`Select Shift layer (active). Use on the Shift key on the shift layer to switch back to the default layer.
`*ShiftLock*`Switch to Caps layer (inactive). Not commonly used; generally double-tap on Shift key is used to access the - caps layer.
`*ShiftedLock*`Switch to Caps layer (active). Use on the Shift key on the caps layer to switch back to the default layer. -
`*Enter*` or Return or Enter key (shape determined by writing system direction)
`*LTREnter*`Return or Enter key (left-to-right script shape)
`*RTLEnter*`Return or Enter key (right-to-left script shape)
`*BkSp*` or Backspace key (shape determined by writing system direction)
`*LTRBkSp*`Backspace key (left-to-right script shape)
`*RTLBkSp*`Backspace key (right-to-left script shape)
`*Menu*`Globe key; display the language menu. Use on the `K_LOPT` key.
`*Hide*`Hide the on screen keyboard. Use on the `K_ROPT` key.
`*ABC*`Select alphabetic layer (Uppercase)
`*abc*`Select alphabetic layer (Lowercase)
`*123*`Select the numeric layer
`*Symbol*`Select the symbol layer
`*Currency*`Select the currency symbol layer
`*ZWNJ*` (iOS) or  (Android)Zero Width Non Joiner (shape determined by current platform)
`*ZWNJiOS*`Zero Width Non Joiner (iOS style shape)
`*ZWNJAndroid*`Zero Width Non Joiner (Android style shape)
`*ZWNJGeneric*`Zero Width Non Joiner (not platform-specific)
`*Sp*`Regular space
`*NBSp*`No-Break Space
`*NarNBSp*`Narrow No-Break Space
`*EnQ*`En Quad
`*EmQ*`Em Quad
`*EnSp*`En Space
`*EmSp*`Em Space
`*PunctSp*`Punctuation Space
`*ThSp*`Thin Space
`*HSp*`Hair Space
`*ZWSp*`Zero Width Space
`*ZWJ*`Zero Width Joiner
`*WJ*`Word Joiner
`*CGJ*`Combining Grapheme Joiner
`*LTRM*`Left-to-right Mark
`*RTLM*`Right-to-left Mark
`*SH*`Soft Hyphen
`*HTab*`Horizontal Tabulation
- -The following additional symbols are also available, but intended for working -with legacy desktop layouts, and not recommended for general use: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Text StringKey CapKey Purpose
`*Tab*`Move to next input element in tab order
`*TabLeft*`Move to previous input element in tab order
`*Caps*`Select caps layer (legacy)
`*AltGr*`Select AltGr (Right-Alt) layer (desktop layout compatibility)
`*Alt*`Select Alt layer (desktop layout compatibility)
`*Ctrl*`Select Ctrl layer (desktop layout compatibility)
`*LAlt*`Select Left-Alt layer (desktop layout compatibility)
`*RAlt*`Select Right-Alt layer (desktop layout compatibility)
`*LCtrl*`Select Left-Ctrl layer (desktop layout compatibility)
`*RCtrl*`Select Right-Ctrl layer (desktop layout compatibility)
`*LAltCtrl*`Select Left-Alt-Ctrl layer (desktop layout compatibility)
`*RAltCtrl*`Select Right-Alt-Ctrl layer (desktop layout compatibility)
`*LAltCtrlShift*`Select Left-Alt-Ctrl-Shift layer (desktop layout compatibility)
`*RAltCtrlShift*`Select Right-Alt-Ctrl-Shift layer (desktop layout compatibility)
`*AltShift*`Select Alt-Shift layer (desktop layout compatibility)
`*CtrlShift*`Select Ctrl-Shift layer (desktop layout compatibility)
`*AltCtrlShift*`Select Alt-Ctrl-Shift layer (desktop layout compatibility)
`*LAltShift*`Select Left-Alt-Shift layer (desktop layout compatibility)
`*RAltShift*`Select Right-Alt-Shift layer (desktop layout compatibility)
`*LCtrlShift*`Select Left-Ctrl-Shift layer (desktop layout compatibility)
`*RCtrlShift*`Select Right-Ctrl-Shift layer (desktop layout compatibility)
- -### Key type - -The general appearance of each key is determined by the key type, which is -selected (in Keyman Developer) from a drop-down list. While generally behavior -is not impacted by the key type, Spacer keys cannot be selected. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Key TypeValueMeaning
Default`0`Any normal key that emits a character
Special`1`The frame keys such as Shift, Enter, BkSp.
Special (active)`2`A frame key which is currently active, such as the Shift key on the shift layer.
Deadkey`8`Does not impact behavior, but colors the key differently to indicate it has a special function, such as a - desktop-style deadkey.
Blank`9`A blank key, which may be used to maintain a layout shape. Usually colored differently. Does not impact - behavior.
Spacer`10`Does not render the key, but leaves a same-sized gap in its place. The key cannot be selected.
- -The colour, shading and borders of each key type is actually set by a style -sheet which can be customized by the page developer. - -### font-family - -If a different font is required for a particular key text, the `font-family` -name can be specified. The font used to display icons for the special keys (as -mentioned above) does not need to be specified, as it will be automatically -applied to a key that uses any of the special key text labels. - -### font-size - -If a particular key cap text requires a different font size from the default for -the layout, it should be specified in em units. This can be helpful if a the key -text is either an unusually large character or, alternatively, a word or string -of several characters that would not normally fit on the key. - -### width - -The layout is scaled to fit the widest row of keys in the device width, assuming -a default key width of 100 units. Keys that are to be wider or narrower than the -default width should have width specified as a percentage of the default width. -For any key row that is narrower than the widest row, the width of the last key -in the row will be automatically increased to align the right hand side of the -key with the key with the right edge of the keyboard. However, where this is not -wanted, a "spacer" key can be inserted to leave a visible space instead. As -shown in the above layouts, where the spacer key appears on the designer screen -as a narrow key, but will not be visible in actual use. - -### pad - -Padding to the left of each key can be adjusted, and specified as a percentage -of the default key width. If not specified, a standard padding of 5% of the key -width is used between adjacent keys. - -### layer - -To simplify correspondence with desktop keyboards and avoid the need for using a -separate keyboard mapping program, touch layout keys can specify a desktop -keyboard layer that the keystroke should be interpreted as coming from. Layer -names of `shift`, `ctrl`, `alt`, `ctrlshift`, `altshift`, `ctrlalt` and -`ctrlaltshift` can be used to simulate use of the appropriate modifier keys when -processing rules. - -### nextlayer - -The virtual keys `K_SHIFT`, `K_CONTROL`, `K_MENU`, etc. are normally used to -switch to another key layer, which is implied by the key code. The left and -right variants of those key codes, and also additional layer-switching keys -mentioned above (`K_NUMERALS`, `K_SYMBOLS`, `K_CURRENCIES`, `K_ALTGR`) can also -be used to automatically switch to the appropriate key layer instead of -outputting a character. However, it is sometimes useful for a key to output a -character first, then switch to a new layer, for example, switching back to the -default keyboard layer after a punctuation key on a secondary layer had been -used. Specifying the `nextlayer` for a key allows a different key layer to be -selected automatically following the output of the key. Of course, that can be -manually overridden by switching to a different layer if preferred. - -Another way the `nextlayer` property can be used is for a non-standard layer -switching key. So, for example, for the GFF Amharic keyboard phone layout, -switching back to the base layer uses a `T_ALPHA` key code, in which `nextlayer` -is set as default. In this case, it is also necessary to add a rule to the -keyboard program: - -```keyman -+ [T_ALPHA] > nul -``` - -to ensure that the key's scan code is ignored by the keyboard mapping. - -When a key in a touch layout definition includes a **Next Layer** control, this -takes precedence over setting layer via the -[`layer`](/developer/language/reference/layer) store (as the **Next Layer** -control is applied once the rule has finished processing). - -### subkey - -Arrays of longpress 'subkeys' or pop-up keys can be defined for any key, and -will appear momentarily after the key is touched if not immediately released. -This provides a major advantage over physical desktop keyboards in that many -more keys can be made available from a single layer, without cluttering up the -basic appearance of the layout. For the GFF Amharic keyboard, we have already -noted how such subkey arrays are used to manage the extra keys that, on the -desktop keyboard, would appear in the shift layer. But they are also used to -provide another way to enter the two different types of each syllable-initial -vowels (glottal or pharyngeal), as a visual alternative to pressing the key -twice. - -The same properties that are defined for standard keys can also be specified for -each subkey except that the width of each key in a subkey array will always be -the same as the width of the key that causes the subkeys to be shown, and key -spacing always uses the default padding value. - -The GFF Amharic keyboard, like many others, is mnemonic, so it is useful to also -display the standard key cap letter that would appear on the key of a desktop -keyboard. This is enabled globally in the On-Screen layout editor and applies to -both the On-Screen keyboard and touch layouts. - -## Representing (and editing) the visual layout with JSON code - -In case you are wondering, 'Why do I need to know that?', the reason is that, -just as with keyboard mapping code, it is sometimes easier to edit a text -specification than to use the GUI layout design tool. Keyman Developer switches -seamlessly between the visual layout tool and the code editor, unless, of -course, careless editing of the code results in invalid JSON syntax! - -The GFF Amharic phone layout code starts as: - -```javascript - { - "phone": { - "font": "Tahoma", - "layer": [{ - "id": "default", - "row": [{ - "id": 1, - "key": [{ - "id": "K_Q", - "text": "ቅ", - "pad": "0" - }, { - "id": "K_W", - "text": "ው" - }, - - . . . -``` - -As long as standard JSON syntax is remembered - nested braces {…}, quoted -strings "…" for both element names and values, element or object arrays in -square brackets […], and no trailing comma after the last element in an array - -it is quite easy to understand a layout, which will usually comprise a list of -two separate JSON objects for tablet and phone. - -Now you're ready to create a great touch layout for your own Keyman keyboard! - -Other articles on developing touch layouts: - -- [Creating a touch keyboard layout for Amharic - part 1](creating-a-touch-keyboard-layout-for-amharic) -- [How to test your keyboard layout — touch and desktop](../test/keyboard-touch-and-desktop) - -You can distribute your keyboard to other users by following the instructions in -this article: - -- [Distribute keyboards to Keyman applications](../distribute/packages) diff --git a/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic.md b/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic.md index 3dc96dfc95..a895225331 100644 --- a/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic.md +++ b/developer/docs/help/guides/develop/creating-a-touch-keyboard-layout-for-amharic.md @@ -1,124 +1,3 @@ --- -title: Creating a Touch Keyboard Layout Part 1 +redirect: . --- - -This article describes the approach taken and some of the issues encountered when adapting the existing GFF‑AMH‑7 Amharic keyboard for easier use on phone and tablet touch screen devices. - -A widely used Keyman Desktop phonetic keyboard for Amharic (developed by Geez Frontier Foundation) was also compiled and made available for use with KeymanWeb. When used with web browsers on desktop computers, the behaviour of the keyboard was identical to use with Keyman Desktop, but use of the same Amharic keyboard on smart phones or other touch screen devices revealed a number of weaknesses in the layout. - -### Background - -The desktop layout has a default layer and a shift layer which are fairly similar: - -![](../../images/touch_amharic_keyboard.png) - - -Several keycaps have more than one Geez script letter, indicating that pressing the key twice changes the character output. Geez script is better understood as an Abugida, rather than an alphabet, since each consonant-vowel syllable is a modification of the original letter rather than having separate letters for consonant and vowel. So when entering Amharic, the form of a consonant changes from the default syllable form to the appropriate syllable character for the consonant and vowel pressed. However, as each vowel can also occur in stand-alone syllables as either pharyngeal or glottal forms, the two separate syllables for each vowel are shown on the "a", "e", "i", "o" and "u" keys. - -But what about the extra characters on the "s" and "h" keys? Amharic (like most Semitic languages) is rich in fricative sounds, and Geez has four separate, distinct phonemes that are roughly similar to the English -"s", and three similar to "h". The desktop layout handles this by using -repeated keystrokes in combination with shift to select the alternate -consonants (before typing the appropriate vowel). That works for a -desktop keyboard, but not for a touch screen device, for which it is -often impractical to hold a shift key while touching another key. - -Small format touch-screen devices such as phones have a further -difficulty in that if they display the full number of key rows and keys -in each row that appear in the desktop layout, the keys are too small -for convenient use. - -On the other hand, touch screen devices offer one very significant -advantage over layouts based on a physical keyboard - it is quite easy -to configure dynamic touch screen layouts to display contextually -appropriate character alternates in separate key windows as each key is -touched. - -### Design goals - -With the above background, the following design goals were set for -developing a touch screen layout for Amharic: -- Maintain the same basic phonetic layout functionality that users are familiar with. -- Instead of having "default" and "shift" layers, design the layout so that all alphabetic text and frequently used punctuation can be entered from a single layer, moving less commonly used punctuation and symbols to the second "symbol" layer. -- Use a dynamic window rather than the shift key to select the initial "s" or "h" consonant for a syllable. -- Use a separate key (adjacent to the space bar) for the Ethiopic word-space character, instead of requiring shift + space to be pressed. -- For tablet devices, increase key size slightly by removing most non-letter keys from each row, moving them either to dynamic ("pop-up") key windows, or to the symbol layer. -- For phones and other small-format devices, further increase the key size by not displaying the digits in the default (alphabetic) layer, and moving many of the less commonly used characters to dynamic windows, reducing the number of key rows by one for each layer. - -### Implementation - -Achieving the design goals required making a number of decisions for -each format (tablet and phone), in particular: - -- Which keys can be removed from the default layer? -- Which keys can be removed from the symbol layer? -- Which "pop-up" keys should be grouped with each base character? - -Keyman Developer 17's Touch Layout editor greatly simplifies the process -of developing the JSON layout file that specifies the touch layout for -each device, making it easy to move keys around, create pop-up key -arrays, and adjust key widths, labels and other parameters. While the -graphical interface does not allow moving entire key rows between layers -or device types, that is easily managed using the code window. - -To keep a keyboard compatible with the desktop version, it is important -to use the same key identifiers and "shift states". So, no matter -whether a particular character occurs in a visible row or in a pop-up -array, it should usually use the same code as on the original desktop -layout keyboard. - -Where a key did not occur in the original layout and does not correspond -to a desktop layout key, identifiers will usually be something like -T\_<name> where <name> will typically be a Unicode character -name, or an obvious contraction of it. Note that this is just a rule of -thumb and key identifiers can be anything that makes sense. Such keys -are distinct from the K\_<name> identifiers that are associated -with physical keys, and should normally have a mapping rule added -explicitly to the mapping program. If no rule is added, output will -default to the keycap text, but this is not recommended. - -All key "rotations" - pressing the same key repeatedly to select from -alternate output characters - in the original desktop keyboard program -are still supported, but have been supplemented by pop-up key arrays, -allowing a user to visually select the wanted character instead of -stepping through alternates. Similarly, Ethiopian numerals can be -selected from a pop-up key array attached to each numeral key, as well -as being output by pressing the single quote key before a digit key. - -The final tablet default keyboard layer, as displayed in the Touch -Layout editor in the previous release of Keyman Developer 10, now appears -as: - -![](../../images/touch_amharic_keyboard_2.png) - -Here the editor is shown with the "s" key selected, displaying the -pop-up key array with the four different Geez characters that can be -produced, each of which will combine as necessary with any subsequently -typed vowel. - -For the small format (e.g. iPhone) layout, the two keyboard layers are: - -![](../../images/touch_amharic_keyboard_3.png) - -For these layouts, the row length has been reduced to the minimum number -of ten keys, moving backspace to another row. The numerals only appear -on the second layer, as is usual with phone layouts. All less-frequently -used keys are now available only in pop-up key windows. - -### Summary - -With these principles guiding all the changes made, the Amharic keyboard -now adapts to various device form factors, making use of device-specific -usability factors, while retaining the same conceptual input model as -the original keyboard. This means that users can use the keyboard layout -on different devices with a minimum of difficulty. These methods should -be applicable to other keyboard layouts. - -Other articles on developing touch layouts: - -- [Creating a touch keyboard layout for Amharic - the nitty gritty](creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty) -- [How to test your keyboard layout — touch and desktop](../test/keyboard-touch-and-desktop) - -You can distribute your keyboard to other users by following the -instructions in this article: - -- [Distribute keyboards to Keyman applications](../distribute/packages) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/index.md b/developer/docs/help/guides/develop/index.md index 8d8490c42c..b9f661c032 100644 --- a/developer/docs/help/guides/develop/index.md +++ b/developer/docs/help/guides/develop/index.md @@ -2,18 +2,16 @@ title: Developing Keyboards --- -[Keyman keyboard tutorial](tutorial) +In version 19, the main keyboard tutorials have been replaced by the Keyman +Developer Walkthrough, which covers all the topics found in the main tutorials +in greater depth. -[An advanced keyboard development example](advanced-keyboard-development-example) +* [The Keyman Developer Walkthrough →](../walkthrough/) -[Creating a simple touch keyboard layout](touch-keyboard-tutorial) +Other tutorials: -[Creating a touch keyboard layout for Amharic - part 1](creating-a-touch-keyboard-layout-for-amharic) +* [An advanced keyboard development example](advanced-keyboard-development-example) +* [Input Method Extensions (IMX)](imx) -[Creating a touch keyboard layout for Amharic - part 2](creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty) - -[Input Method Extensions (IMX)](imx) - ------------------------------------------------------------------------- - -[Keyman Developer 16 Tutorial](https://lingtran.net/Keyman-Developer-16-Tutorial) (external on Lingtran.net) \ No newline at end of file +> [!NOTE] +> The old tutorials can still be found in earlier versions of the Keyman Developer help; see the version selector at the top right of this page. diff --git a/developer/docs/help/guides/develop/touch-keyboard-tutorial/gestures.md b/developer/docs/help/guides/develop/touch-keyboard-tutorial/gestures.md index b09d5919cf..7505708ee1 100644 --- a/developer/docs/help/guides/develop/touch-keyboard-tutorial/gestures.md +++ b/developer/docs/help/guides/develop/touch-keyboard-tutorial/gestures.md @@ -1,26 +1,5 @@ --- -title: Using Gestures in Keyman Developer +redirect: .. --- -Keyman Developer offers **Longpress** keys, **Flicks**, and **Multitaps** for touch keyboard layout. To allow gestures onto your keyboard, go to the Touch layout tab and define the keys as follows: - -Keyman Developer touch layout gestures - -## Tips - -***Flicks** and **long presses** can both be used in a single keyboard. In this scenario, it is recommended to use flicks in only one direction—south (down). Long presses work well alongside this pattern. See, for example, [sil_euro_latin](https://help.keyman.com/keyboard/sil_euro_latin/3.0.3/sil_euro_latin#toc-mobile-keyboard-layout). - * Another helpful tip seen in the sil_euro_latin keyboard is using south-flicks on the base and shift layers corresponding to the numeric/symbol layer, this aids in both memorization and discovery. -* **Flicks** in multiple directions are possible, but currently Keyman does not support hints for multiple directions, so they are not very discoverable. -* **Long presses** are more discoverable, but **flicks** are faster. We suggest using south flicks along with long presses, and including the flick output in the long press for maximum discoverability and optimum ergonomics. - -## Caution - -* **Flicks** near screen edges tend to be problematic--once you drag off the screen, then Keyman can no longer tell that you are flicking (or you may end up activating system controls on the bottom edge): - * On the bottom row, south flicks are not recommended. - * On the top row, we have the banner space reserved in order to be able to support flicks and long presses up into that region of the screen. - * Left/right screen edges, horizontal flicks are not the best practice. - -## See also - -* The [Winchus keyboard](https://help.keyman.com/keyboard/winchus/1.4/winchus#guia-rapida-celular) -* The [GFF Amharic keyboard](https://help.keyman.com/keyboard/gff_amharic/3.2.1/gff_amharic#toc-using-this-keyboard) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/touch-keyboard-tutorial/index.md b/developer/docs/help/guides/develop/touch-keyboard-tutorial/index.md index acfe3efcec..7505708ee1 100644 --- a/developer/docs/help/guides/develop/touch-keyboard-tutorial/index.md +++ b/developer/docs/help/guides/develop/touch-keyboard-tutorial/index.md @@ -1,60 +1,5 @@ --- -title: Creating a Simple Touch keyboard +redirect: .. --- -## Introduction and design - -If you have experience in designing Keyman keyboards for computers, the -interface for designing mobile keyboards looks very similar, but it -hides the reality of additional steps necessary for mobile keyboards. -This tutorial attempts to walk you through the process. - -The [Quick French tutorial](../tutorial/) shows how to create a simple -desktop keyboard for typing accented characters used in French and other -European languages. It is possible to create a touch screen format of -that keyboard, but it is probably unnecessary. The default keyboards for -both Android and iOS devices have a way to type these accented -characters. Press and hold on a vowel, and a popup menu will give you a -choice of accents to put on that letter. - -For this tutorial we will demonstrate something usable for the Fulfulde -language cluster spoken across many Sahelian countries of Africa. -Fulfulde is usually written using the Latin alphabet, but there are a -few characters added to the usual list of alphabetical characters. So -this is a useful example for any language wanting to add a few -characters to the standard Latin keyboard. Here are the characters we -are going to add, together with their Unicode values. - -| | | | | | | | | | -|-----|----------|-----|----------|-----|-----|----------|-----|----------| -| `ɓ` | `U+0253` | `Ɓ` | `U+0181` | | `ɗ` | `U+0257` | `Ɗ` | `U+018A` | -| `ŋ` | `U+014B` | `Ŋ` | `U+014A` | | `ƴ` | `U+01B4` | `Ƴ` | `U+01B3` | - -Here we will likely want to proceed differently than with the desktop -keyboard. The usual approach for a desktop keyboard is to create a -deadkey. The keyboards I have used for Fulfulde (going back to decades -ago) used the / key as the deadkey. -/b gave ɓ, -/d gave ɗ, and so on. - -It would be possible to use that desktop keyboard logic on touch -screens. But your mobile device users will find these rules annoying. - -Instead of two keys they would probably have to press four, since the -standard alphabetical keyboard on most touch devices does not have the -slash key. So they would have to press the key to switch to the numeric -keyboard, then press slash, then press the key to switch back to the -alphabetical keyboard, and then the letter. What touch screen users would -appreciate is something that uses the great feature of touch screens, -the long press or press and hold on a letter, to see analogous letters. - -So we’ll set up a touch screen keyboard that lets you -* press and hold ‘d’ to see the two hooked d characters -* press and hold ‘b’ to see the hooked b characters, and so on. - -[Next: Making, testing and distributing the touch -keyboard](making-touch-keyboard) - -## See also - -* Tips for using [gestures](gestures) in Keyman Developer +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/touch-keyboard-tutorial/making-touch-keyboard.md b/developer/docs/help/guides/develop/touch-keyboard-tutorial/making-touch-keyboard.md index 5039acb262..7505708ee1 100644 --- a/developer/docs/help/guides/develop/touch-keyboard-tutorial/making-touch-keyboard.md +++ b/developer/docs/help/guides/develop/touch-keyboard-tutorial/making-touch-keyboard.md @@ -1,361 +1,5 @@ --- -title: Making a touchscreen keyboard +redirect: .. --- -## Setting up your Keyman project - -This is a useful convention for keeping track of your files: - -1. Create a folder on your hard drive for all your Keyman developer - files -2. In that folder, create a folder for this project, named after the - language. Use all lowercase letters for compatibility with other - platforms. -3. Now create a project in Keyman Developer with the same name as the - new folder, and save it inside the new folder - -Now you will be able to use this project to organize and create any -files for desktop, mobile, web or other. It also facilitates uploading -the files to the Keyman website later on. - -## Add touch to an existing keyboard or create a new keyboard? - -You can add a mobile touchscreen keyboard to an existing desktop -keyboard, or you can create a new touchscreen keyboard from scratch. You -should be aware that there will be cross-over between mobile and desktop -keyboards. (In Keyman terms, "desktop" includes laptop computers or any -device with a physical keyboard). Your mobile device can have an -external keyboard, which will use the desktop Keyman keyboard. So the -Keyman strategy is to always bundle touch keyboards with desktop -keyboards to make them work on multiple platforms. - -If creating from scratch, you click the New icon in the Keyman Developer -toolbar (or select File > New from the menu), and specify the file -name for your keyboard. We recommend a name using only lowercase -letters, numbers and underscore. I’ll choose “mobile_fulfulde.kmn” . - -![choose new file -type](../../../images/simpleTouchKeyboard_1.png) - -## Adding the required metadata - -After creating the file, Keyman Developer will ask you to name the -keyboard. This name can include spaces and upper case letters if -desired. I’ll name this one “Fulfulde for Mobile”. - -![keyboard -metadata](../../../images/simpleTouchKeyboard_2.png) - -The first thing you need to do is to tell Keyman Developer this keyboard -will include some kind of mobile device.  You do this in the Targets -list just below the keyboard name. I’ll select “mobile ” in the list, -(towards the end). You see in the picture above that Keyman Developer -checked the “windows” box by default, I can uncheck that or leave it -checked if I am going to add a Windows keyboard to this set. - -![mobile target](../../../images/simpleTouchKeyboard_3.png ) - -This will include all mobile devices, both Android and iOS, both phones -and tablets. It is possible if needed to select Android only or iOS only -if needed, and to develop a different keyboard layout for tablets than -for phones, but for this example, with only a few characters needed to -be added to the default keyboards, there is no need for that kind of -complexity. - -(If you are adding a mobile layout to an existing keyboard file, you -would open that file in Keyman Developer, go to the Targets box and -check “mobile” or whatever mobile targets you wanted to specify, then -follow along from here). - -## Adding the touch optimized feature - -The next step is to add the touch-optimised feature to our keyboard -setup. If you scroll to the bottom of the details tab, there is the list -of features to add. I’ll click the Add button and choose “touch -optimised keyboard.” - -![touch-optimised](../../../images/simpleTouchKeyboard_4.png) - -Keyman developer asks me to choose one of three templates for the mobile -layout. - -![three templates](../../../images/simpleTouchKeyboard_5.png) - -The “template-latin” layout includes many accented characters, like the -default keyboards for Android and iOS do. The “template-basic” layout -has no extra characters, and the template-traditional has a few extra -characters (mostly punctuation symbols if you long-press period or full -stop). For this example, I’ll choose “template-basic” because accented -characters are not needed for Fulfulde. But if I knew that many eventual -users might want to be able to type French or other European languages -as well as Fulfulde, and wouldn’t like to have to switch the keyboard to -do so, I could choose “template-latin”. - -## Defining one or several touch layouts - -I select the template and click OK. Keyman Developer now adds a new tab -in the left column, the Touch Layout tab. - -![touch layout](../../../images/simpleTouchKeyboard_6.png) - -That is where we need to go now to add characters to our touch layout. -But before doing that, there is one important thing to take note of in -the touch layout. By default, Keyman Developer has created a layout for -phones and another layout for tablets. They all start out the same, but -as I add characters, I will have to make sure I add all the characters -to both layouts, or I’ll discover that my keyboard does not work for all -device sizes. - -In the image, you see in the Platform box that Keyman Developer is currently showing the -tablet layout. This box is where I’d choose which layout I’d design in. - -But I’m going to make this keyboard simple, and just have one layout for -both tablets and phones. So in the platform box, I am going to click -the “minus” button, to delete the tablet layout. When there is only one -mobile layout, Keyman Developer will compile that layout for all mobile -devices. (I could also have chosen to delete the phone layout and done -my layout design in the tablet layout). - -![platform list](../../../images/simpleTouchKeyboard_7.png) - -## Adding longpress characters - -Now I can start adding characters. I’ll click on the “y” key in the -layout, then I’ll look at the “longpress keys” area at the lower -left. - -![add longpress](../../../images/simpleTouchKeyboard_8.png) - -I click that, and Keyman Developer adds a new key below the keyboard -layout. - -![longpress added](../../../images/simpleTouchKeyboard_9.png) - -I'm going to use this key for the y with hook. I click inside it to make it active, then I’ll go look for my y -with hook character in the character map to the right. If I type “y -hook” in the search box, Keyman Developer shows the character I’m -looking for. - -![adding keycap](../../../images/simpleTouchKeyboard_10.png) - -If I double click on the lower case y with hook, that copies the character -to the keycap box of my new key. (I could also click and drag the character from the character map to the key). - -![keycap added](../../../images/simpleTouchKeyboard_11.png) - -## New key info - -There are several important pieces of information that got copied over. If we -look at the properties of the new key to the right, we see that this new key has -the “text” ƴ (what appears on the keycap), the “Unicode value” U+01B4 and the -“ID” U_01B4. All of these were copied from the character map. - -NOTE: If you copy one character from the character map to a new key, then -realize you copied the wrong character, dragging a second character may not -replace all the needed information into the key. If a key has a character in it -already, it works better to hold Ctrl as you drag the new character -into it. - -I could add the other three characters; hook b, hook d, and eng, as longpress -characters as well. I could select the regular letter I want to longpress, -click plus in the longpress keys area and copy the needed character. Here for -example is the b with hook: - -![keycap added](../../../images/simpleTouchKeyboard_12.png) - -After I have added my four lowercase characters as longpress keys, the keyboard -looks like this. Even when I don't have that letter selected, I can see which -keys have longpress keys by the dot beside the letter. - -![keycap added](../../../images/simpleTouchKeyboard_12-2.png) - -[See the Keyman Language guide on virtual keys](../../../../language/guide/virtual-keys#toc-virtual-keys-and-touch-layouts) - -## Adding uppercase characters - -I could do two different things for the upper case letters. I could add them as -longpress keys beside their lowercase equivalents, by pressing the plus key -again to add a second longpress character to each letter. - -This would mean users would not have to press Shift to be able to type the upper -case hook y. But since a user needs to press Shift for all the regular Latin -upper case letters, it might make more sense to put the uppercase letters into -the Shift layer. - -I can change to the shift layer by finding the layer box at lower left, and -choosing `shift` instead of `default`. - -![changing to shift layer](../../../images/simpleTouchKeyboard_13.png) - -Now I see the upper case letters on the keyboard, and I can add longpress -characters to these in the same way I did on the default layer. I click the -letter, then click `+` to add a key, then copy the character info from the -character map. Adding my upper case y hook to Y would look like this: - -![new key added to row](../../../images/simpleTouchKeyboard_14.png) - -(If I had clicked on the green triangle to the left of my first key, the -new key would be added to the left of that key). - -For this new key, I go through the same steps. I click in the empty box -on the new key, then double click the upper case y with hook in the -character map to put that in the keycap. I also change the code of this -new key to “U_01B3” - -![keycap and code added to new -key](../../../images/simpleTouchKeyboard_15.png) - -## Another option for upper case characters - -I might also add the upper case character to a longpress character on -the upper-case Y key, because some users will press the Shift key then -look for the letter to type. To do this, I change the layer at the top -of the tablet layout to "shift" from "default". - -![changing -layer](../../../images/simpleTouchKeyboard_15b.png) - -Now I click the Y key, and add a longpress character, then add the upper -case y with hook to the keycap and add the keycode as shown before. - -![key added to longpress -Y](../../../images/simpleTouchKeyboard_16b.png) - -You can design your keyboard either way, with the upper case characters -in the same longpress row as the lower case, or in a longpress row off -of the shift layer. The rest of this tutorial shows the upper case -characters in the same row as the lower case, but I don't mean to -present this as the best way. If you do put upper case characters in the -shift layer, you'll have to remember to change the layer back to -"default" when you want to add a lower case letter, then back to "shift" -when adding an upper case letter. You could put the upper case -characters in both places, if you think that best. - -Now I’ll add the two d hook characters as a longpress popup for the d -key. I click the d key in the layout, click “Add longpress popup”, add -the lower case hook d to the keycap and change the code to “U_0257”; -then click the plus sign to add a second key, add the upper case hook D -to the keycap and change its code to “U_018A”. The end result should -look like this: - -![longpress row on -d](../../../images/simpleTouchKeyboard_16.png) - -I’ll do the similar step to add two characters as a longpress popup for -“b” - -![longpress row on -b](../../../images/simpleTouchKeyboard_17.png) - -And two characters as a longpress popup for “n”. (Tip, to search for ŋ -in the character map, type “eng”). - -![longpress row on -n](../../../images/simpleTouchKeyboard_18.png) - -When no keys are selected in the keyboard layout, I can still see which -ones I have set up longpress popups for, because Keyman Developer shows -a faint gray line at the top right corner of the key. So you should have -a faint diagonal line on your y, d, b and n keys. - -![lines on longpress -keys](../../../images/simpleTouchKeyboard_19.png) - -## Replacing the Unicode and Code automatically - -1. Hold the Ctrl key while dragging and - dropping a character from the Character Map to the touch layout - editor, and it will replace the Code as well as the character. -2. Hold the Shift key while dropping, and it - will only add the character to the key. -3. Finally, hold - Ctrl+Shift, this - will add the character to the key AND update the Code to match the - full set of characters represented on the key. - -## Compiling your keyboard - -Now click Save to save your work, and compile the keyboard. (Keyboard -> Compile Keyboard, or press F7). Hopefully you’ll see it compiled -with no error messages: - -![successful -compile](../../../images/simpleTouchKeyboard_20.png) - -If you see a warning like: - -``` -Warning: line 0  warning 2092: Key " T_new_579" on layer "default", platform "phone", is a custom key but has no corresponding rule in the source. -``` - -This shows you forgot to enter the correct keycode for a new key you -added. Double check your longpress popup keys for one with a “T_new_NNN” -code, and add in the desired “U_NNNN” code. - -You might also see a message like - -``` -Error: line 0  error 405A: Key " U+0181" on "phone", layer "default" has an invalid identifier. -``` - -This shows you attempted to change the keycode but mistyped the code. -I’ve gotten this more than once, because I am used to typing `U+0181`to -refer to a Unicode value, but the correct syntax for a keycode in Keyman -Developer is `U_0181` - -# Testing your keyboard - -Other Keyman help pages describe how you can test your keyboard: - -- [On a virtual device in the Chrome web browser on your - computer](../../test/keyboard-touch-mobile-emulator) -- [On your own device accessing the keyboard over the - network](../../test/keyboard-touch-and-desktop) - -If your device cannot connect to your computer on the local network (for -instance if your computer is on a wired office network and your device -is on the wireless office network), the above technique for sharing may -not work. You can put your keyboard in a package and share it over the -Internet with your device, as described below. - -# Packaging and distributing your keyboard - -Another Keyman help file describes [how to build a package -file.](../../distribute/tutorial) - -## BCP 47 tags for Fulfulde - -[Step 3](../../distribute/tutorial/step-3) of the package building -tutorial describes adding the BCP 47 language tag to your package. When -I came to the step of adding a tag for Fulfulde, I had to do some -research. I naively thought "Fulfulde" was a clear enough label for the -language. It is not, since it is a language chain rather than one -language. The BCP 47 tag in many cases is the same as the [SIL -Ethnologue code](https://www.ethnologue.com), so that is where I had to -go to find the tags I needed. In the end I added four tags for four -Fulfulde languages: - -![BCP 47 tags](../../../images/simpleTouchKeyboard_36.png) - -I also added the script designator `Latn` for Latin script. This is -recommended for Windows, which sometimes fails to install the desktop -keyboard if there is not a script designator on the BCP 47 tag. We -recommend that you always put in the script tag unless there is a -specific reason not to. - -Some languages have only two letters in their BCP 47 tag. For instance, -the Hausa language has an Ethnologue code `hau` but the BCP 47 tag is -`ha`. Keyman Developer knows about this, and will change the tag to `ha` -if I put in the Ethnologue tag. - -# Next steps - -The two following articles on Amharic describe a more complex -touchscreen example where quite frequently two keys are pressed to get -one distinct character. (Amharic is a Abugida or syllabary script, where -one character can represent a consonant and following vowel). - -- [Creating a touch keyboard layout for Amharic - part - 1](../creating-a-touch-keyboard-layout-for-amharic) -- [Creating a touch keyboard layout for Amharic - part - 2](../creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/index.md b/developer/docs/help/guides/develop/tutorial/index.md index 3642ddc1ed..e27c01cf2f 100644 --- a/developer/docs/help/guides/develop/tutorial/index.md +++ b/developer/docs/help/guides/develop/tutorial/index.md @@ -1,56 +1,3 @@ --- -title: Keyboard Tutorial +redirect: .. --- - -[Step 1: Planning the Keyboard](step-1) - -[Step 2: Writing the Header](step-2) - -[Step 3: The Keyboard Header](step-3) - -[Step 4: The Keyboard Body](step-4) - -[Step 5: Rules with Context](step-5) - -[Step 6: Stores, 'any', and 'index'](step-6) - -[Step 7: Testing the Keyboard](step-7) - -[Step 8: Deadkeys](step-8) - -[Step 9: The Finished Keyboard](step-9) - -## Overview - -Welcome! In this tutorial, you will learn the basics of Keyman keyboards -and create a simple French keyboard which can be used with any physical -keyboard layout. - -The keyboard will use a basic English layout, and add some deadkeys to -define vowel diacritics and a few other characters. - -While this tutorial is based on a physical keyboard such as used on a -desktop or laptop computer, the principles of the keyboard language that -you will learn are applicable to developing touch layouts as well. - -This keyboard will use Unicode. Unicode is a character encoding standard -that supports most of the world's scripts, and includes support for -user-defined scripts. Unicode is the accepted standard for text encoding -in modern applications and operating systems. - -In Keyman Developer keyboard source files, Unicode characters are -specified with `U+xxxx`, where `xxxx` is a four-digit hexadecimal -number. - -At the bottom of each page in the tutorial, will be a link to both the -previous page and the next page. You can use these links to work your -way through the tutorial. You may also find links to reference -information, which you can select to learn more about a particular -aspect of creating Keyman keyboards. - -## Let's begin - -Let's get started! Move on to the next topic to begin the first step, -planning the keyboard. - -- [Continue with Step 1: Planning the Keyboard](step-1) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-1.md b/developer/docs/help/guides/develop/tutorial/step-1.md index 96db7592ee..7505708ee1 100644 --- a/developer/docs/help/guides/develop/tutorial/step-1.md +++ b/developer/docs/help/guides/develop/tutorial/step-1.md @@ -1,71 +1,5 @@ --- -title: Step 1: Planning the Keyboard +redirect: .. --- -## Choosing the characters - -First of all, we need to decide which characters we want the keyboard to -produce. Next, we must find out the codes used to represent them, using -a program such as Character Map, or with the Character Map in Keyman -Developer (go to **View**, **Character Map**). - -French uses the same 26 letters as English, with some additions. As our -keyboard is based on English, we only need to work with these additional -letters. Note that for completeness, we will design our keyboard to -produce a few other accented vowels that are not used in French. Also, -we want our keyboard to include the angled quotes `«` and `»`. - -These characters, with both uppercase and lowercase forms, are listed in -the table below along with their Unicode codes. - -| | | | | | | | | | -|-----|----------|-----|----------|-----|-----|----------|-----|----------| -| `À` | `U+00C0` | `à` | `U+00E0` | | `Á` | `U+00C1` | `á` | `U+00E1` | -| `È` | `U+00C8` | `è` | `U+00E8` | | `É` | `U+00C9` | `é` | `U+00E9` | -| `Ì` | `U+00CC` | `ì` | `U+00EC` | | `Í` | `U+00CD` | `í` | `U+00ED` | -| `Ò` | `U+00D2` | `ò` | `U+00F2` | | `Ó` | `U+00D3` | `ó` | `U+00F3` | -| `Ù` | `U+00D9` | `ù` | `U+00F9` | | `Ú` | `U+00DA` | `ú` | `U+00FA` | -| `Â` | `U+00C2` | `â` | `U+00E2` | | `Ä` | `U+00C4` | `ä` | `U+00E4` | -| `Ê` | `U+00CA` | `ê` | `U+00EA` | | `Ë` | `U+00CB` | `ë` | `U+00EB` | -| `Î` | `U+00CE` | `î` | `U+00EE` | | `Ï` | `U+00CF` | `ï` | `U+00EF` | -| `Ô` | `U+00D4` | `ô` | `U+00F4` | | `Ö` | `U+00D6` | `ö` | `U+00F6` | -| `Û` | `U+00DB` | `û` | `U+00FB` | | `Ü` | `U+00DC` | `ü` | `U+00FC` | -| `Ý` | `U+00DD` | `ý` | `U+00FD` | | `Ç` | `U+00C7` | `ç` | `U+00E7` | -| `«` | `U+00AB` | `»` | `U+00BB` | | | | | | - -If you are not familiar with the hexadecimal (base-16) numbering system, -don't worry: you can use the Character Map in Keyman Developer to find -the character you want, and then drag-and-drop or copy-and-paste its -character code into your keyboard. - -Note that you must be careful to use the right character: The Unicode -standard has many characters with the same shape as another, but a -different meaning; an example of this is the Greek capital letter Sigma -(`U+03A3` Σ) and the mathematical summation symbol (`U+2211`, ∑). An application -supporting Unicode would treat these two characters differently. If in -doubt whether a character is the right one, you can look up the -reference tables at [www.unicode.org](http://www.unicode.org/). - -## Designing the layout - -After choosing the characters we want our keyboard to use, we must -decide how we want the user to be able to enter them. For some -languages, you might replace each letter on the English keyboard with a -letter from the language. In this case, however, most of the letters are -accented vowels, we will use two keystrokes for each: one for the -accent, and one for the vowel. - -| Character | Keystrokes | -|-------------|-------------------------------| -| `À, à, ...` | back-quote (`), then the vowel key. | -| `Á, á, ...` | quote ('), then the vowel key. | -| `Â, â, ...` | caret (^), then the vowel key. | -| `Ä, ä, ...` | double-quote ("), then the vowel key. | -| `Ç, ç` | quote ('), then lower- or uppercase C. | -| `«, »` | two less-than (<<) or greater-than (>>) symbols. | - -Now that we have decided which character to use and how the user can -enter them, we can start to write the keyboard. - -- [Continue with Step 2: Writing the Header](step-2) -- [Back to the Introduction](index) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-2.md b/developer/docs/help/guides/develop/tutorial/step-2.md index 5867973fb3..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-2.md +++ b/developer/docs/help/guides/develop/tutorial/step-2.md @@ -1,53 +1,5 @@ --- -title: Step 2: Writing the Header +redirect: . --- -## Overview of a keyboard file - -A keyboard file is divided into two sections: the **header** and the -**rules** section. The header section defines the name of the keyboard, -its bitmap, and other general settings. The rules are used to define how -the keyboard responds to keystrokes from the user, and are divided into -groups. We will start by writing the header. - -## The keyboard header - -The keyboard header is the first part of a keyboard; it consists of -statements that help Keyman identify the keyboard and set default -options for it. Each statement in the header must be on a separate line. -While there is no technical requirement to put header statements at the -start of a keyboard source file, keeping them there helps you identify -them easily, and keeps them consistent with keyboard programs other -people might write. - -We will begin to write the keyboard. If Keyman Developer is not already -running, start it now. Create a new keyboard file, navigate to the -**Layout** tab, and click on the **Code** tab at the bottom of the -screen to switch to the Code view. - -Type or paste the following code into the keyboard file. This is the -header of our keyboard file. - -```keyman -c Simplified French Keyboard for Keyman 9.0 -c -c This keyboard program uses a simplified set of keys -c for typing French, especially for those who don't know the -c standard French keyboard. -c -c NOTE: This keyboard was created from the Keyman keyboard -c programming tutorial. - -store(&Version) "9.0" c This keyboard is for use with Keyman 9.0 -store(&Name) "Quick French" -store(&Bitmap) "qfrench.ico" -store(&MnemonicLayout) "1" c This keyboard uses a mnemonic layout. - -begin Unicode > use(Main) -``` - -An explanation of the various parts of the header follows on the next -page. - -- [Continue with Step 3: The Keyboard Header](step-3) -- [Back to Step 1: Planning the Keyboard](step-1) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-3.md b/developer/docs/help/guides/develop/tutorial/step-3.md index 81777aec6a..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-3.md +++ b/developer/docs/help/guides/develop/tutorial/step-3.md @@ -1,99 +1,5 @@ --- -title: Step 3: The Keyboard Header +redirect: . --- -## Comments - -```keyman -c Simplified French Keyboard for Keyman 9.0 -``` - -Most of the header in this example is made up of -[comments](/developer/language/guide/comments). A comment is used -to make notes about the keyboard, or to provide information on the -workings of the keyboard. The comments are readable by anyone looking at -the source code of the keyboard. - -A comment always starts with a lowercase `c`, followed by one or more -spaces, and continues to the end of the line. Keyman Developer will -ignore comments when compiling a keyboard. - -Comments can take up a whole line, or can start in the middle of the -line. The latter is useful for making short notes about individual -lines. As you can see we have used both kinds of comments in the header. - -## The `&Version` store - -```keyman -store(&Version) "9.0" c This keyboard is for use with Keyman 9.0 -``` - -The [`&Version` store](/developer/language/reference/version) -identifies the Keyman version for which this keyboard was written; this -keyboard is for use with Keyman 9.0. The `&Version` store is an optional -part of the keyboard header, but if present, it should be the first -store in the file. - -## The `&Name` store - -```keyman -store(&Name) "Quick French" -``` - -The [`&Name` store](/developer/language/reference/name) specifies -a descriptive name for the keyboard, which can be up to eighty -characters long. The name we have given to this keyboard is -`"Quick French"`. The `&Name` store is not required but is highly -recommended! - -## The `&Bitmap` store - -```keyman -store(&Bitmap) "qfrench.ico" -``` - -The optional [`&Bitmap` store](/developer/language/reference/bitmap) -tells Keyman which image to use for the keyboard's icon. The picture -should be in the standard Windows .ico format, and should contain at -least a single 16x16 pixel image. It can also contain higher resolution -images for high resolution "High DPI" displays. If you use a modern icon -editor, the icon can use alpha transparency. -For this keyboard we will be using the following bitmap: -![](../../../images/tutorial_keyboard_qfrench.gif); it is -found in the Keyman Developer folder, under -`Samples\Examples\qfrench.ico` - you should copy it into the same folder -in which you will save your keyboard. - -## The `&MnemonicLayout` store - -```keyman -store(&MnemonicLayout) "1" -``` - -The [`&MnemonicLayout` store](/developer/language/reference/mnemoniclayout) tells Keyman that -the layout is meant to conform to the user's keyboard layout; for -example, if the user presses the quote key ' on -their keyboard (whether they are using a US English, UK English, French, -German, Swedish, or other keyboard) it should work in the same way. The -opposite of this is a positional layout (which is the default if this -store omitted), which is intended for keyboards for which there is not -necessarily a correspondence between what is printed on the physical -keyboard and what is output when that key is pressed. - -## The `begin` statement - -```keyman -begin Unicode > use(Main) -``` - -The [`begin` statement](/developer/language/reference/begin) tells -Keyman which group of rules to process first when it receives a -keystroke. The use of multiple groups is an advanced feature, and -unnecessary for this tutorial, so we will use a single group, called -`Main`. The `begin` statement is required in every keyboard, and marks the -start of the keyboard body. The `begin` statement also tells Keyman -which encoding to use for the keyboard. Nearly all keyboards will use -`Unicode`, today. - -- [Continue with Step 4: The Keyboard Body](step-4) -- [Back to Step 2: Writing the Header](step-2) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-4.md b/developer/docs/help/guides/develop/tutorial/step-4.md index e8a861ae1c..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-4.md +++ b/developer/docs/help/guides/develop/tutorial/step-4.md @@ -1,102 +1,5 @@ --- -title: Step 4: The Keyboard Body +redirect: . --- -The body of the keyboard is the most important part: it determines the -behaviour of the keyboard. The body consists of groups, which in turn -contain one or more rules which define the responses of the keyboard to -certain keystrokes. - -## Groups - -There are two types of groups: -* groups that process the keys pressed and the context. -* groups that process only the context. - -For simple keyboards, the latter type of group will not be required. A group begins -with a [`group` statement](/developer/language/reference/group), and -ends either at the start of another group, or at the end of the keyboard -file. - -We will only use one group in the Quick French keyboard, called `Main`. -We mark the start of it with the `group` statement below. Add this line -to the keyboard if it's not already there. - -```keyman -group(Main) using keys -``` - -The `using keys` clause tells Keyman that this group will process -keystrokes. - -## Basic Rules - -A rule tells Keyman the output to produce for a certain input. A rule -consists of three parts: the **context**, the **key**, and the -**output**. - -* The **context** specifies the conditions under which a rule will act. If -what is shown in the document to the left of the cursor matches the -context of a rule, the rule will be processed. -* The **key** specifies which keystroke the rule will act upon. -* The **output** determines the characters that are produced by a rule. -The output replaces the matched context in the document. - -## Simple rules - -The simplest rules in Keyman consist of just a key and output, as below. -(The examples in this section are just for illustration, and do not form -part of the Quick French keyboard). - -```keyman -+ "a" > "ä" -``` - -In this rule, the key is a, and the output is `"ä"`. A simple rule -begins with a plus sign, followed by the key, a greater-than symbol -(suggesting "becomes"), and finally the output. As you might guess, this -rule will change a lowercase a key typed by the -user into **ä**. - -The key and output can be written as a character in single or double -quotes (as above), or as its Unicode character code, or using a named -constant. The rule above could have also been written any of the -following ways, among others: - -```keyman -+ 'a' > 'ä' - -+ U+0061 > U+00E4 - -store(ADIERESIS) 'ä' -+ 'a' > $ADIERESIS -``` - -You can also write the key in one form and the context in another. - -## Rules with longer output - -The output of a rule is not limited to a single character. You could, -for example, write a rule such as the following: - -```keyman -+ "f" > "ph" -``` - -This would change any f keys typed into **ph**. -If the output of a rule consists of more than one character, you can -write the characters in different ways if necessary, with a space -separating each part. You can specify multiple characters in quotes, but -if you use the Unicode codes to write the characters, you must separate -each with a space: - -```keyman -+ "f" > U+0070 U+0068 - -+ "f" > U+0070 "h" -``` - -These rules are functionally identical to the one [further above](#toc-simple-rules). - -- [Continue with Step 5: Rules with Context](step-5) -- [Back to Step 3: The Keyboard Header](step-3) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-5.md b/developer/docs/help/guides/develop/tutorial/step-5.md index 88a76bce34..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-5.md +++ b/developer/docs/help/guides/develop/tutorial/step-5.md @@ -1,76 +1,5 @@ --- -title: Step 5: Rules with Context +redirect: . --- -## Rules with Context - -Very often we want a keyboard to produce different output based on more -than just the last keystroke. For example, in the Quick French keyboard, -we want the key e to produce one of è, é, -ë, ê, or just e, depending on what was typed immediately before -it. To do this we must make our rules look at the context. - -The context is the output from previous rules; that is, the characters -that are displayed on the screen. We can make a rule work with only -certain context by putting this before the plus sign in the rule: - -```keyman -"^" + "e" > "ê" -``` - -With this rule, whenever an e is typed, if it -was preceded by a caret (^), the output will be ê. It is important -to remember that the context consists of **output -from previous rules**, not the previous keystrokes. To emphasize -this point, consider the four rules below: - -```keyman -+ "a" > "b" -+ "b" > "c" -"b" + "c" > "d" -"c" + "d" > "e" -``` - -With these rules, typing b c would produce the -output `cc`, and not `d`, as you might initially expect. This is because -the key b is converted by the second rule into -the output `c`, while the third rule expects a context of b, and not -c; we would have to type a c to get `d`. - -However, if a key has no matching rule, the output will be the same as -the key: so the output `e` will be produced for either of the inputs c d (because c by itself has no rule), and b d. - -## Continuing the Quick French keyboard - -Now we know how to create context-dependent rules, we can continue -making the Quick French keyboard. Let's start with the rules for -acute-accented characters, using the ANSI codes from the table we -prepared earlier: - -```keyman -c lowercase characters with acute accent -"'" + "a" > U+00E1 -"'" + "e" > U+00E9 -"'" + "i" > U+00ED -"'" + "o" > U+00F3 -"'" + "u" > U+00FA -"'" + "y" > U+00FD - -c uppercase characters with acute accent -"'" + "A" > U+00C1 -"'" + "E" > U+00C9 -"'" + "I" > U+00CD -"'" + "O" > U+00D3 -"'" + "U" > U+00DA -"'" + "Y" > U+00DD -``` - -We can also create similar rules for the other thirty-odd accented -characters. - -As you can see, even for a simple keyboard like this we quickly end up -with a large number of rules, which makes for clumsiness. We can make -things simpler using stores, and the `any()` and `index()` statements. - -- [Continue with Step 6: Stores, `any()`, and `index()`](step-6) -- [Back to Step 4: The Keyboard Body](step-4) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-6.md b/developer/docs/help/guides/develop/tutorial/step-6.md index 95ade8767c..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-6.md +++ b/developer/docs/help/guides/develop/tutorial/step-6.md @@ -1,116 +1,5 @@ --- -title: Step 6: Stores, any(), and index() +redirect: . --- -When we have many similar rules, as in the last example on the previous -page, we can group them together into one rule by using stores. A store -is a set of characters that are grouped under a single name. Stores are -used in rules with the [`any()`](/developer/language/reference/any) and -[`index()`](/developer/language/reference/index) statements. We create a -store with a [`store()` statement](/developer/language/reference/store): - -```keyman -store(vowels) "aeiou" -``` - -This creates a store called `vowels`, which contains the five lowercase -vowels. -> #### Note: -We could also have written the content of the store -using ANSI or Unicode character codes, in the same way as the output. - -The `any()` statement is used to match a character from a specific -store. For example, the following rule will replace any vowel with a -period, when used with the store above: - -```keyman -+ any(vowels) > "." -``` - -The `any()` statement can be used in the context or in the key part of a -rule. It cannot be used in the output. - -The second statement that is used with stores is the `index()` -statement. It is usually used in the output of a rule, and will output -the character from a particular store at the same position as the -character matched by a specified `any()` statement. This is best shown -with an example; this rule will convert all input to uppercase: - -```keyman -store(lowercase) "abcdefghijklmnopqrstuvwxyz" -store(uppercase) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -+ any(lowercase) > index(uppercase,1) -``` - -When a letter, such as j is typed, the `any()` -statement finds its position in the `lowercase` store; the `index()` -statement then gets this index from the `any()` statement, and outputs -the character at the same position in the `uppercase` store, in this -case `J`. - -The `index()` statement has two parts: the store from which it takes the -output character, and the offset of the `any()` statement that it gets -the character position from. This offset is found by counting the -characters and statements in the context and key parts of the rule up to -the `any()` statement. Again, a few examples may help to illustrate -this: - -```keyman -"a" + any(somestore) > index(otherstore,2) c The 'any' statement - c is character #2 -"ab" any(somestore) + "c" > index(otherstore,3) c The 'any' statement - c is character #3 - -c Here the 'index' statement references the second 'any' statement used, -c which is character #4 -U+0041 any(somestore) "B" + any(otherstore) > index(thirdstore,4) - -c You can have multiple 'index' statements in the output, which can -c reference the same or different 'any's -any(store1) + any(store2) > index(store1,2) index(store2,1) index(store3,2) -``` - -## Using stores in the Quick French keyboard - -We can now reduce the number of rules needed for the Quick French -keyboard by using stores. We will make five stores: one for the -unaccented vowels, and one each for vowels with acute accents, grave -accents, circumflexes, and diereses. For clarity, the `group()` -statement is repeated below: - -```keyman -group(Main) using keys - -store( plainvowels ) 'a' 'e' 'i' 'o' 'u' 'A' 'E' 'I' 'O' 'U' -store( acutevowels ) U+00E1 U+00E9 U+00ED U+00F3 U+00FA U+00C1 U+00C9 U+00CD U+00D3 U+00DA -store( gravevowels ) U+00E0 U+00E8 U+00EC U+00F2 U+00F9 U+00C0 U+00C8 U+00CC U+00D2 U+00D9 -store( circumvowels ) U+00E2 U+00EA U+00EE U+00F4 U+00FB U+00C2 U+00CA U+00CE U+00D4 U+00DB -store( dresisvowels ) U+00E4 U+00EB U+00EF U+00F6 U+00FC U+00C4 U+00CB U+00CF U+00D6 U+00DC - -"'" + any( plainvowels ) > index( acutevowels, 2 ) -"`" + any( plainvowels ) > index( gravevowels, 2 ) -"^" + any( plainvowels ) > index( circumvowels, 2 ) -'"' + any( plainvowels ) > index( dresisvowels, 2 ) -``` - -This is far clearer than the long list of rules that we used earlier. -Obviously we should add one or two more ordinary rules to produce uppercase -and lower-case ç, ý, and also the angled quotes « and ». Then we -will have almost finished the keyboard: - -```keyman -"'" + "y" > U+00FD c Acute-accented Y -"'" + "Y" > U+00DD - -"'" + "c" > U+00E7 c C-cedilla -"'" + "C" > U+00C7 - -"<" + "<" > U+00AB c Angled quotes -">" + ">" > U+00BB -``` - -All we need to do now is to test the keyboard. - -- [Continue with Step 7: Testing the Keyboard](step-7) -- [Back to Step 5: Rules with Context](step-5) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-7.md b/developer/docs/help/guides/develop/tutorial/step-7.md index 2432bb76f4..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-7.md +++ b/developer/docs/help/guides/develop/tutorial/step-7.md @@ -1,52 +1,5 @@ --- -title: Step 7: Testing the Keyboard +redirect: . --- -# Compiling the Keyboard - -Before we can test the keyboard, we must compile it. Choose -Keyboard, Compile -Keyboard or press F7 to compile the -keyboard. The Message window will display the results of the -compilation; if you have no typing errors, the keyboard should compile -successfully. - -If there are any mistakes, an error message will be displayed in the -Message window, which will tell you the line on which the error -occurred. - -## Compiling the Keyboard - -After compiling the keyboard successfully, we can start testing it. -Choose Debug, -Start Debugging or press -F5 to begin testing. The Keyboard debug window -will appear. - -Now we test that all the rules operate as expected. To test the rules, -we type the keystrokes that will give us the output; for example, we can -type a quote ' followed by one of -A, E, -I, O, -U, or Y to test the -uppercase acute-accented vowels. Similarly we can test the other -accents, and C-cedilla (`Ç`) and the angled quotes. If the rules are -correct, all this should work as we wanted. - -Testing the rules in isolation like this will show if the rules are -correct or not, but won't show other possible errors that might occur in -everyday usage of the keyboard. For example, look at what happens if you -type the following quote: - -> `'Alors Alice demande, "Où est mon chat ?"'` - -As you can see, it comes out incorrectly as: - -> `Álors Alice demande, Öù est mon chat ?"'` - -The problem occurs when we have a word in quotes that begins with a -vowel: the keyboard will convert it to an accented vowel. We will need -to come up with a solution to this problem. - -- [Continue with Step 8: Deadkeys](step-8) -- [Back to Step 6: Stores, `any()`, and `index()`](step-6) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-8.md b/developer/docs/help/guides/develop/tutorial/step-8.md index 52f532ce76..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-8.md +++ b/developer/docs/help/guides/develop/tutorial/step-8.md @@ -1,78 +1,5 @@ --- -title: Step 8: Deadkeys +redirect: . --- -## Solving the Problem - -Probably the easiest solution to the problem which we encountered on the -last page is to design the keyboard so that the user types a quote key -twice when they want to produce a quote, but once when they want to use -it as an accent. However, we cannot simply use the rule: - -```keyman -"'" + "'" > "'" -``` - -This will certainly produce a single quote after it's typed twice; -however it will still produce the same error, because the following -keystroke will continue to swallow the quote character from the context. -We need to distinguish between the output of this rule, when the user -wants a quote, and that of a single quote press, when the user wants to -place an accent on a vowel. To implement this behaviour, we use -[deadkeys](/developer/language/reference/deadkey). - -## Deadkeys - -A deadkey is like a character that is used in the context or output but -never appears on the screen. We use deadkeys like this: - -```keyman -+ "'" > deadkey(quote) - -c Handle acute accents -deadkey(quote) + any( plainvowels ) > index( acutevowels, 2 ) - -c Handle a single quote -deadkey(quote) + "'" > "'" -``` - -Note that for the sake of convenience, a deadkey can also be written in -a short form: - -```keyman -dk(quote) c This is identical to deadkey(quote) -``` - -Type the three rules above in place of the existing rule for acute -accents in the keyboard so far. If you test the keyboard now, you will -find that the error no longer occurs. This is because accented vowels -are only produced after the deadkey, and no deadkey is output if the -user types a quote key twice. - -But we've introduced another difference to the keyboard now: the quote -is no longer displayed before you type the vowel. This is because we are -converting the quote to a deadkey. If we prefer, we can still -distinguish between rules in the above manner and display the quote, if -we just add a quote before the deadkey, like this: - -```keyman -+ "'" > "'" dk(quote) - -c Handle acute accents -"'" dk(quote) + any( plainvowels ) > index( acutevowels, 3 ) - -c Handle a single quote -"'" dk(quote) + "'" > "'" -``` - -However, we will not use this technique for the Quick French keyboard. - -Now we can make changes so that all the other accents use deadkeys as -well, for consistency, and add rules to output the accent character by -typing the key twice. - -The Quick French keyboard is now complete. The full source is on the -next page. - -- [Continue with Step 9: The Finished Keyboard](step-9) -- [Back to Step 7: Testing the Keyboard](step-7) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/develop/tutorial/step-9.md b/developer/docs/help/guides/develop/tutorial/step-9.md index 03e00a2787..5e2725a24e 100644 --- a/developer/docs/help/guides/develop/tutorial/step-9.md +++ b/developer/docs/help/guides/develop/tutorial/step-9.md @@ -1,66 +1,5 @@ --- -title: Step 9: The Finished Keyboard +redirect: . --- -## The Quick French Keyboard - -Here is the completed keyboard: - -```keyman -c Simplified French Keyboard for Keyman 9.0 -c -c This keyboard program uses a simplified set of keys -c for typing French, especially for those who don't know the -c standard French keyboard. -c -c NOTE: This keyboard was created from the Keyman keyboard -c programming tutorial. - -store(&Version) "9.0" c This keyboard is for use with Keyman 9.0 -store(&Name) "Quick French" -store(&Bitmap) "qfrench.ico" -store(&MnemonicLayout) "1" c This keyboard uses a mnemonic layout. - -begin Unicode > use(Main) - -group( Main ) using keys - -c Store the upper and lowercase vowels with different accents -store( plainvowels ) 'a' 'e' 'i' 'o' 'u' 'A' 'E' 'I' 'O' 'U' -store( acutevowels ) U+00E1 U+00E9 U+00ED U+00F3 U+00FA U+00C1 U+00C9 U+00CD U+00D3 U+00DA -store( gravevowels ) U+00E0 U+00E8 U+00EC U+00F2 U+00F9 U+00C0 U+00C8 U+00CC U+00D2 U+00D9 -store( circumvowels ) U+00E2 U+00EA U+00EE U+00F4 U+00FB U+00C2 U+00CA U+00CE U+00D4 U+00DB -store( dresisvowels ) U+00E4 U+00EB U+00EF U+00F6 U+00FC U+00C4 U+00CB U+00CF U+00D6 U+00DC - -c Output deadkeys only for the accent keys pressed -+ "'" > dk(quote) c Quote for acute accent -+ "`" > dk(bkquote) c Backquote for grave accent -+ "^" > dk(caret) c Caret for circumflex -+ '"' > dk(dbquote) c Double-quote for dieresis - -c Rules for accented vowels -dk(quote) + any( plainvowels ) > index( acutevowels, 2 ) -dk(bkquote) + any( plainvowels ) > index( gravevowels, 2 ) -dk(caret) + any( plainvowels ) > index( circumvowels, 2 ) -dk(dbquote) + any( plainvowels ) > index( dresisvowels, 2 ) - -c Rules for other characters -dk(quote) + "y" > U+00FD c Acute-accented Y -dk(quote) + "Y" > U+00DD - -dk(quote) + "c" > U+00E7 c C-cedilla -dk(quote) + "C" > U+00C7 - -"<" + "<" > U+00AB c Angled quotes -">" + ">" > U+00BB - -c Rules for the accent character itself (type it twice) -dk(quote) + "'" > "'" c Quote -dk(bkquote) + "`" > "`" c Backquote -dk(caret) + "^" > "^" c Caret -dk(dbquote) + '"' > '"' c Double-quote - -c End of keyboard -``` - -- [Back to Step 8: Deadkeys](step-8) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/__index.txt b/developer/docs/help/guides/distribute/__index.txt new file mode 100644 index 0000000000..807ccfd46b --- /dev/null +++ b/developer/docs/help/guides/distribute/__index.txt @@ -0,0 +1,4 @@ +-install-kmp-android.md +-install-kmp-ios.md +-packages.md +-tutorial \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/index.md b/developer/docs/help/guides/distribute/index.md index 4ffe845c38..f69eee8972 100644 --- a/developer/docs/help/guides/distribute/index.md +++ b/developer/docs/help/guides/distribute/index.md @@ -1,10 +1,8 @@ --- -title: Distributing keyboards +title: Package Tutorial --- -- [Package development tutorial](tutorial) (Keyman for Windows, Keyman for macOS, Keyman for mobile apps) -- [Distribute keyboards to Keyman applications](packages) +In version 19, the Package Tutorial has been replaced by the Keyman +Developer Walkthrough, which covers all the topics in greater depth. -## See also - -- [Keyman Engine](/developer/engine/) \ No newline at end of file +* [The Keyman Developer Walkthrough →](../walkthrough/08-preparing-keyboard-package) diff --git a/developer/docs/help/guides/distribute/install-kmp-android.md b/developer/docs/help/guides/distribute/install-kmp-android.md index bdba196c90..5e2725a24e 100644 --- a/developer/docs/help/guides/distribute/install-kmp-android.md +++ b/developer/docs/help/guides/distribute/install-kmp-android.md @@ -1,78 +1,5 @@ --- -title: Installing Custom Keyboards to your Android Device +redirect: . --- -## Overview - -In [Keyman for Android 10.0](/products/android/10.0/), we added the ability to -easily download/share custom keyboards to your Android device. - -## Installing a custom keyboard - -To install a custom keyboard, you will need a link to download the -keyboard package. If you have already copied the kmp file onto the -Android device, skip to Step 2. - -If you want to build and dev your own keyboard, you will need some -technical skills for this, and can read our full step-by-step -instructional on how to do this [here](packages). - -Once you have a website or email with a link to the keyboard package, -follow these steps on your Android device to download and install the -keyboard package into the Keyman for Android application: - -## Step 1) Click the link to save your custom keyboard package file - -The link in this example is for Khmer Angkor keyboard. - -![](../../images/dist-url-screen-ap.png) - -## Step 2) Add Keyboard from Device - -Once the KMP file is on your device, you will need to browse to the KMP -file and select it. From the Keyman menu, select "Settings". From the -Keyman Settings menu, select "Add Keyboard from Device". - -![](../../images/settings-language-ap.png) - -The device will launch a file browser where you'll browse to the -directory of your KMP file. A common places to look is the "Downloads" -folder. - -![](../../images/dist-file-browser-ap.png) - -Selecting the KMP file should bring you to Step 3) - -## Step 3) Grant Keyman for Android access to storage (Android 6.0+ only) - -On Android 6.0 (Marshmallow) and higher, mobile apps need to request -permission to access storage. Keyman for Android needs access to read -storage for installing the KMP file. At the dialog, select "ALLOW". Once -authorized, Keyman for Android won't need to ask for storage permission -again, unless the user revokes or uninstalls the app. - -![](../../images/dist-storage-permission-ap.png) - -Older versions of Android grant Storage permissions at app installation -time, so those users can skip this step. - -## Step 4) Keyboard Package welcome screen - -Keyman for Android will parse the metadata in the package. If the -keyboard package includes a "welcome.htm" file, this will be displayed -at the confirmation to install the keyboard package - -![](../../images/dist-welcome-ap.png) - -If "welcome.htm" is not included, a generic page with the package ID and -package version will be shown. - -Click the left "Install" button to install the entire keyboard package - -## Step 5) The keyboard is successfully installed! - -All the keyboards in the package are installed as a group. In this -example, the package only has the "Khmer Angkor" keyboard, so it becomes -the active keyboard - -![](../../images/dist-install1-ap.png) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/install-kmp-ios.md b/developer/docs/help/guides/distribute/install-kmp-ios.md index de4d3a64cb..5e2725a24e 100644 --- a/developer/docs/help/guides/distribute/install-kmp-ios.md +++ b/developer/docs/help/guides/distribute/install-kmp-ios.md @@ -1,53 +1,5 @@ --- -title: Installing Custom Keyboards to your iPhone or iPad +redirect: . --- -## Overview - -In version 10 of Keyman for iPhone and iPad, we added the ability to easily download custom keyboards to your iOS device. - -## Installing a custom keyboard - -To install a custom keyboard, you will first need a link to the keyboard -package on a website or in your email. - -If you want to build and dev your own keyboard, you will need some -technical skills for this, and can read our full step-by-step -instructional on how to do this [here](packages). - -Once you have a website or email with a link to the keyboard package, -follow these steps on your iPhone or iPad to download and install the -keyboard package into the Keyman for iPhone and iPad application: - -## Step 1) Click the link to your custom keyboard package file - -The link in this example is for GFF Amharic 7 keyboard. - -![](../../images/dist-url-screen-i.png) - -Safari will display an option to open the KMP file with Keyman - -![](../../images/dist-kmp-open-i.png) - -## Step 2) Click Open in "Keyman" - -Keyman for iPhone and iPad will parse the metadata in the package. If -the keyboard package includes a "welcome.htm" file, this will be -displayed at the confirmation to install the keyboard package - -![](../../images/dist-welcome-i.png) - -If "welcome.htm" is not included, a generic page with the package ID and -package version will be shown. - -## Step 3) Click the top right "Install" button - -The keyboard from the keyboard package is successfully installed! - -![](../../images/dist-kmp-success-i.png) - -All the keyboards in the package are installed as a group. In this -example, the package only has the "GFF Amharic 7" keyboard, so it -becomes the active keyboard - -![](../../images/dist-install1-i.png) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/packages.md b/developer/docs/help/guides/distribute/packages.md index 5bc1e7de80..5e2725a24e 100644 --- a/developer/docs/help/guides/distribute/packages.md +++ b/developer/docs/help/guides/distribute/packages.md @@ -1,131 +1,5 @@ --- -title: Distribute keyboards to Keyman Applications +redirect: . --- -## Overview - -Keyboard package files contain one or more keyboards, along with readme -files, fonts (if your keyboard requires a custom font), and any other -files you wish to include. You should create a package file to bundle -your keyboard with fonts and help into a simple, single file that is -easy for an end-user to install. - -Internally, as well as your own files, the package file will contain -metadata files "kmp.inf" and "kmp.json", which list the details Keyman -needs to install the package. The package file is a ZIP compatible -archive. - -> ### Tip -You can distribute keyboards and lexical models in package files, but -you can't include both in the same package file. - -#### Keyman for Windows - -Keyman for Windows can install package files, including installing fonts, -creating Start Menu shortcuts, and adding appropriate registry entries -for uninstallation. - -On Windows, the context menu for a package file has one additional -entry: "Install". - -#### Keyman for macOS - -Keyman for macOS can install package files with fonts and keyboards, and -shortcuts in the package will be available through the keyboard's entry -in Keyman Configuration. - -#### Keyman for Android and Keyman for iPhone and iPad - -Keyman mobile applications can install the same package files as Keyman -for Windows, as long as the package includes keyboards for touch layouts. - -## Package file contents - -A package can have a variety of different files contained within. The -following files and file types are recognized by the package installer: - -\*.kmx (Keyman for Windows, Linux, and macOS only) -: Keyboard files. Each of these will be installed. Keyman - Configuration will not allow installation or uninstallation of a - single keyboard from a package. They will always be treated as a - group for installation and uninstallation. - -\*.kvk (Keyman for Windows, Linux, and macOS only) -: On Screen Keyboard files, associated with each keyboard file. - -\*.js (mobile only) -: Touch layout Keyboard files. When Keyman mobile applications install - a keyboard package, all included keyboards will be installed as a - group. With Keyman Developer 10, the keyboard version information is - in kmp.json, and no longer within the JS file names. - -welcome.htm -: Introductory help for the keyboard, HTML format. This will normally - be displayed when the package is installed by the user, and is also - the entry point for help when accessed via Keyman's help system or - Keyman Configuration. - -readme.htm -: Displayed before a package is installed, together with brief - metadata about the package, to allow the user to determine if they - wish to continue installation of the package. - -kmp.inf (Legacy versions of Keyman) -: A Windows .ini format file that lists each of the files in the - package, together with metadata. - -kmp.json -: A JSON format file contains metadata for the keyboard package such - as package version, keyboard versions, and lists each of the files - in the package. For more explanation of the structure of the JSON - file, please read the - [metadata](../../reference/file-types/metadata) documentation. - -\*.ttf, \*.otf, \*.ttc -: Truetype font files that will be installed with the package, and - uninstalled when the package is removed. On mobile, these fonts will - be available only within the Keyman app and the on-screen-keyboard, - not in other apps. - -## Share the keyboard package file - -> ### Tip -Read [Step 2: Organizing the Keyboard Files](../../../keyboards/github/step-2) -to know which files to include or exclude in the keybord folder. - -Once the keyboard package .kmp file is created, you can share them via -external storage devices (USB drive, SD card, etc). You can also share -the package file via a cloud storage system (Google Drive, Dropbox or -similar service), then share the link to your device via text, note or -email. Alternatively, you can upload the .kmp file to a public facing -website. For this example, the keyboard package for Khmer Angkor is -being uploaded: - -1. khmer_angkor.kmp (the keyboard package .kmp file) - -## Putting the keyboard package on a website - -Once all the files have been uploaded, you will need to provide a link -to the keyboard package .kmp file for your device to download and -install. This can either be a link on a web page, or a link in an email. -In this tutorial, a very simple .html web page with a link to the -khmer_angkor.kmp file is created: - -``` markup - - - - - Custom Keyboard URL - - -``` - -The link must be in the format `http://` or `https://` - -Upload the web page to your public facing website. Once done, you can -install the keyboard package onto your mobile devices by following these -steps: - -- [Installing custom keyboards to your iPhone or iPad](install-kmp-ios) -- [Installing custom keyboards to your Android device](install-kmp-android) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/index.md b/developer/docs/help/guides/distribute/tutorial/index.md index 89bc2eb2a9..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/index.md +++ b/developer/docs/help/guides/distribute/tutorial/index.md @@ -1,36 +1,5 @@ --- -title: Package Tutorial +redirect: .. --- -[Step 1: What do we include?](step-1) - -[Step 2: Creating Additional Files for the Package](step-2) - -[Step 3: Creating a package and adding files](step-3) - -[Step 4: Filling in package details](step-4) - -[Step 5: Shortcuts](step-5) - -[Step 6: Compiling, testing and distributing a Package](step-6) - -## Overview - -Welcome! In this tutorial, you will learn how to create a -[package](../../../reference/file-types/kmp). A package is a collection -of files, compressed into a single file, just like a ZIP file. It is -designed to make installation of keyboards, fonts and related -documentation straightforward for the end user. When done, the package -can be installed into Keyman for Windows through a simple dialog. Keyman for -mobile apps can also download and install keyboards through the keyboard -package. - -We will be creating a Khmer Angkor package. You can make your own -package based on the Quick French keyboard from the [keyboard tutorial](../../develop/tutorial). - -### Let's begin - -Let's get started! Move on to the next topic to begin the first step, -choosing what to include in the package. - -[Step 1: What do we include?](step-1) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-1.md b/developer/docs/help/guides/distribute/tutorial/step-1.md index a18fce49ac..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-1.md +++ b/developer/docs/help/guides/distribute/tutorial/step-1.md @@ -1,35 +1,5 @@ --- -title: Step 1: What do we include? +redirect: .. --- -What is the purpose of a package? To make installation of a keyboard, -fonts, documentation, and on screen keyboard as straightforward as -possible for the end user. - -We need to keep this goal in mind as we work on all the aspects of a -package. - -A good package will: - -1. Collect the keyboard and font files together for simple installation -2. Include Start Menu items for documentation - -A great package will also: - -1. Include a 'readme' visible before install. -2. Include a 'welcome.htm' file which is displayed after install. -3. Include an On Screen Keyboard if relevant. -4. Include documentation on use of the keyboard. - -Packages uploaded to the Tavultesoft website will get basic icon ratings -reflecting their ease of install/use: - -- ![](../../../images/tutorial_package_includesfonts.gif) includes fonts -- ![](../../../images/tutorial_package_includesdocs.gif) includes documentation -- ![](../../../images/tutorial_package_includesosk.gif) includes on screen keyboards -- ![](../../../images/tutorial_package_includeswelcome.gif) includes welcome.htm - -In general, the more icons that a package earns, the easier that end -users will find it to start using. - -[Step 2: Creating Additional Files for the Package](step-2) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-2.md b/developer/docs/help/guides/distribute/tutorial/step-2.md index 7ed9aea576..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-2.md +++ b/developer/docs/help/guides/distribute/tutorial/step-2.md @@ -1,127 +1,5 @@ --- -title: Step 2: Creating Additional Files for the Package +redirect: .. --- -You should create or select some additional files for a package. Below -are a list of the typical files that you would create for or include in -a package. - -readme.htm - -: A short description of the package, its use restrictions, and what - it includes. Try to keep the readme under 10 lines long. The readme - is displayed in the package install dialog and should be an html - file for optimal formatting. - - > ### Tip - As the package has not been installed at this stage, and you are using fonts that may not yet be available on the target device, you should use CSS @font-face declarations to ensure that the text is readable on all devices. - - Create the HTML file in any HTML editor. - - > ### Tip - If using Microsoft Word, choose HTML (clean) when saving to create a smaller file. - - Note, if your HTML editor puts images into a subfolder, you will need to edit the HTML source so that all files are in the same folder -- the package builder will not maintain subfolders. You can easily edit the HTML source in Keyman Developer. - - Also, if your welcome or readme files use embedded external images, stylesheets, javascript or other files, you will need to add these files to your package as well. - -welcome.htm - -: When including an introductory help file in your package, you must - name the file welcome.htm. This file will be detected during install - and displayed (in a window roughly two thirds of the user's screen - width) after the package install completes successfully. Make sure - that you design your HTML file so that it can be resized to fit the - user's screen - avoid extra wide tables or wide fixed width - elements. - - At this stage of the installation, fonts in the package have been installed, so you can include text that uses those fonts. - - Welcome.htm will also be accessible after installation from Keyman Configuration under the Package Options menu, and from the Keyboard Help item and On Screen Keyboard toolbar button. - - The intention of welcome.htm is to provide instructions on getting started with your keyboards. - - > ### Tip - Useful information to include in welcome.htm is: - - key sequences - especially for characters that may not be immediately obvious. - - names of fonts in the package. - - names of keyboards in the package. - - links to additional help on your website or more extensive documentation files in the package. - - a link to an official distribution site for your package (even - if it is the Keyman website) - so that users know where to find - the latest version of your package. - - You should avoid including instructions for the use of Keyman - itself - although a basic "click the Keyman icon and choose Quick - French" would be helpful. - - > ### Tip - If you want links to your website to open in the user's preferred - browser, preface the href link with `link:`, e.g. - `website` - The `link:` sceheme will open the referred file in the default - application - that is, a web browser for URLs and links, Notepad for - .txt files, Adobe Reader for PDFs. You can use `link:` to open any - of the files in the package, e.g. `link:docs.pdf` will open the file - docs.pdf in Adobe Reader or the default PDF reader on the system. - - To save you the effort of writing a welcome and readme file for the - Quick French example, we have placed some in the Samples/QFrench - folder. - - If you create documents in other formats, for example PDF or - printable documentation, you should link to that in the welcome.htm. - - > ### Tip - You can include multiple "welcome.htm" files for different languages - by appending a hyphen and the BCP 47 language code to the filename, - for example welcome-fr.htm for French. - -Fonts - -: A font is the single most important item to include with a keyboard - – if the characters of the language you are supporting are not in - fonts included with target operating systems. Installing fonts is - tedious, so make sure that your users don't have to locate and - install fonts themselves! - - .TTF, .OTF, and .TTC fonts will be installed by the package - installer, and uninstalled when the package is uninstalled. A list - of the fonts installed is displayed in the Install Package dialog. - -Keyboards - -: Add the .kmx compiled Keyman keyboards to the package. You can add - multiple keyboards to the package, but be judicious. - - > ### Tip - Don't forget to add the On Screen keyboard .KVK file associated with - your keyboard to the package. KVK files are not compiled into the - .KMX file -- although the .ICO/.BMP is. - - Add the .js compiled Keyman touch layout keyboards to the package. - -Documentation - -: The two preferred documentation formats are HTML and PDF. You should - avoid .DOC, .RTF, and other formats -- .DOC files in particular are - not recommended due to the possibility of macro viruses. - - Remember that HTML files can be displayed on any computer without - additional software. PDF files require Adobe Reader or a compatible - PDF viewer application. You may choose to include both and HTML - documentation - PDF documents often print better than HTML - documents, but HTML documentation is more accessible and translates - better to on-screen or web use. - - > ### Tip - If you use HTML, don't forget to also add all the included files - such as images and stylesheets! - -Splash Image -: The splash image is a 140x250 pixel image that is displayed when the - package is installed, at the left of the Package Install dialog. - Including a splash image makes your package look more professional - and polished, so a splash image is recommended! - -[Step 3: Creating a package and adding files](step-3) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-3.md b/developer/docs/help/guides/distribute/tutorial/step-3.md index 657f2cd02b..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-3.md +++ b/developer/docs/help/guides/distribute/tutorial/step-3.md @@ -1,31 +1,5 @@ --- -title: Step 3: Creating a package and adding files +redirect: .. --- -We are finally ready to open up the Package Editor and create the new -package. - -- In the Project Window in Keyman Developer, click the **Packages** tab, and click **New Package...**. Enter the path and filename of the package you are creating. - -> ### Tip -This tutorial makes a package named `khmer_angkor.kps`, but you could call yours `qfrench.kps`. - -A package source file will have the extension .kps, and will be compiled in a file with extension .kmp. - -After you click OK, the Package Editor will open with the Files tab visible. - -![](../../../images/tutorial_distribute_keyboard_3_files.png) - -- In the Files tab, click **Add...** to add - all the files we discussed in the previous step to the package. You - can add multiple files at once, and from multiple folders. When the - package is compiled, all the files will be placed in the same folder - within the package. -- If your package includes .js touch layout keyboards, you can - associate fonts and languages in the Keyboards tab. A valid [BCP 47 language tag](../../../reference/bcp-47) must be set or the keyboard will not install on your mobile device. - -![](../../../images/tutorial_distribute_keyboard_3.png) - -You could stop here. This would be a completely valid package, but it would not be as good as it could be. So let's continue on to the next step, and fill in some descriptions of the package. - -[Step 4: Filling in package details](step-4) \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-4.md b/developer/docs/help/guides/distribute/tutorial/step-4.md index fcebc042f6..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-4.md +++ b/developer/docs/help/guides/distribute/tutorial/step-4.md @@ -1,63 +1,5 @@ --- -title: Step 4: Filling in package details +redirect: .. --- -Click on the Details tab in the Package Editor. You should fill in as -many details as you can on this page. - -![](../../../images/tutorial_distribute_keyboard_details.png) - -Package Name - -: The Package Name will be displayed in the package install dialog, - and within Keyman Configuration, wherever the package is - referred to. - -Readme File - -: Select the readme file from the list of files you added in the - previous step. Remember that it should be a HTML file for optimum - clarity. - -Version - -: A version number for the package is important - it helps the your - users know that they are using the most recent update of your - package. The version format you should use is `1.0`. When making a - major change to your package or keyboards in your package, increment - the first part and set the second part to, e.g. `2.0`; when making a - bug fix or a minor update, increment the second part, e.g. `1.1`. - -Version numbers should be in the form `major.minor[.subversion]`. - Subversion is optional but is helpful for small bug fix releases. - Each of the sections of the version should be an integer. Keyman - for Windows does integer comparisons on the version numbers, so, for - example, version `2.01` is regarded as older than version `2.2`. - Alphabetic or date formats should be avoided as the installer for - the keyboard cannot determine which version is older reliably. - -Copyright - -: Enter copyright details for your package and keyboards. Keep this - reasonably short or it won't be clear for end users. - -Author - -: Enter your name or the name of your company. - -Email - -: Enter a contact email address where package users can contact you. - If you don't want to be contacted via email, leave this field empty - -Website - -: Enter the name of the website where you will have information about - this keyboard. If you want to host it on keyman.com, you could enter - `https://keyman.com/` - -Image file -: Select the splash image file that you created in Step 2 from the - list of files in your package. - -[Step 5: Shortcuts](step-5) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-5.md b/developer/docs/help/guides/distribute/tutorial/step-5.md index f8c89fd635..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-5.md +++ b/developer/docs/help/guides/distribute/tutorial/step-5.md @@ -1,49 +1,5 @@ --- -title: Step 5: Shortcuts +redirect: .. --- -Click on the Shortcuts tab in the Package Editor. - -![](../../../images/tutorial_distribute_keyboard_shortcuts.png) - -While it may be a good idea to include Start Menu shortcuts for your -package, on recent versions of Windows these are not very visible to end -users. This means that you should ensure that all instructions are -available through the **welcome.htm** file as well. The Start Menu -shortcuts were designed originally for Windows-based keyboard packages -and work slightly differently in macOS. - -You should consider adding the following items to the Start Menu: - -- Documentation shortcuts -- Welcome.htm shortcut - -> ### Note -While Keyman Developer 8.0 and earlier versions of the documentation -advised including an uninstall shortcut to the package, this is no -longer recommended. Users should uninstall your package from Keyman -Configuration. Adding an uninstall shortcut to the package adds -confusion to the Start Menu search on Windows, and is not compatible -with macOS keyboards. - -Click **New** to add a new shortcut to the -package. Enter a description for the shortcut, and select the program or -file to start from the Program list. Four predefined program entries -(Start Product), (Product Configuration), (Product Help) and (About -Product) will be translated into the appropriate shortcuts to start -Keyman for Windows tasks as described. - -> ### Note -In Keyman 6 and earlier, the predefined targets $KEYMAN\keyman.exe and -$KEYMAN\kmshell.exe were available. These are translated to (Start -Product) and (Product Configuration), respectively, in Keyman -7.0 and later versions. - - - -> ### Tip -Packages are not listed in the Control Panel Add/Remove Programs applet -with Keyman 7.0 and later versions. Packages can be uninstalled -through the Start Menu shortcut or from Keyman Configuration. - -[Step 6: Compiling, testing and distributing a Package](step-6) +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/distribute/tutorial/step-6.md b/developer/docs/help/guides/distribute/tutorial/step-6.md index 374584c3e1..7505708ee1 100644 --- a/developer/docs/help/guides/distribute/tutorial/step-6.md +++ b/developer/docs/help/guides/distribute/tutorial/step-6.md @@ -1,68 +1,5 @@ --- -title: Step 6: Compiling, testing and distributing a Package +redirect: .. --- -In the Package Editor, click on the **Compile** tab. - -![](../../../images/tutorial_distribute_keyboard_compile.png) - -Click **Compile Package** to compile the -package into a .kmp file. Compiling takes all the files listed for the -package, compresses them (using a .ZIP-compatible format) and adds the -package information, all into a single file. If any files are not -available, an error will be listed in the Messages window. - -After compiling, you can test the package installation in Keyman -Desktop, by clicking **Install Package**. You -should test that all the keyboards and fonts install successfully, that -the Readme and Welcome files are displayed during the install, and that -the documentation is accessible to the end user. Make sure that the On -Screen Keyboard installs with your keyboards, and that the shortcuts are -correctly listed and working in the Start Menu. - -> ### Advice -The distribution model for Keyman keyboards is changing. We now -recommend distributing source for keyboards through the [Keyman Cloud Keyboard Repository](/developer/keyboards/). The instructions here -remain, but the binary distribution model is deprecated. - -## Distributing a package on the Keyman Cloud Keyboard Repository - -Once you have tested the package to your satisfaction, it is time to -distribute it. We recommend uploading your keyboard package to the -[Keyman Cloud Keyboard Repository](/developer/keyboards/) - -## Distributing a package on your own website - -If you distribute a package on your own site, we have the following -recommendations: - -1. Ensure the MIME type on the web server or folder for .KMX and .KMP - files is set up to application/octet-stream. Without this, .KMP - files may be recognised as .ZIP files -- this is not helpful to the - end user as it will be opened in the wrong application. If you can't - make this change, consider hosting the keyboard package on the - Tavultesoft website to make things easier for your end user. -2. Avoid putting the .KMP file in an archive (e.g. .ZIP) or - self-expanding archive (.EXE) - this makes it harder for end users - to install. A .KMP file is already compressed (it is actually just a - ZIP archive file!) and you won't save much space by recompressing - it. -3. Include a link to the Keyman download page: - `http://keyman.com/desktop/` - -## Distributing a package by email - -Attaching the KMP file directly to an email may be blocked for security -reasons. As mentioned above, a KMP file is basically a ZIP file and -mobile keyboard data is in JavaScript, this is a combination that looks -suspicious to many email servers. You can upload it to a Google drive, -and email a link for downloading the file - -You may need to do some exploring to get your mobile device to load the -keyboard from the KMP file into Keyman. The device may not open the file -directly, claiming it is an unrecognized type. If you look for other -options to open the file, hopefully you can get it to Keyman. For -example, in iOS, I had to tap on the three dots to the right, then -choose "Open in" and then I could choose "Copy to Keyman." In Android, I -had to download the file to my device, then open the KMP file in a file -manager before I could install it in Keyman. \ No newline at end of file +(Replaced by new walkthrough in v19) \ No newline at end of file diff --git a/developer/docs/help/guides/index.md b/developer/docs/help/guides/index.md index 55604780ad..f36d44bbd3 100644 --- a/developer/docs/help/guides/index.md +++ b/developer/docs/help/guides/index.md @@ -5,9 +5,8 @@ title: Keyman Developer Guides Need help using Keyman Developer? You'll find everything you need here, including product documentation, frequently asked questions and tutorials. - [Introduction to Keyman Developer](intro) -- [Developing Keyman keyboards](develop/) -- [Testing Keyman keyboards](test/) -- [Distributing Keyman keyboards](distribute/) +- [The Keyman Developer Walkthrough](walkthrough) - [Developing Keyman lexical models (for predictive text and autocorrect)](lexical-models/) +- [Testing Keyman keyboards and lexical models](test/) - [Distributing Keyman lexical models](lexical-models/distribute/) -- [Keyman Developer command line tools guide](command-line) \ No newline at end of file +- [Keyman Developer command line tools guide](command-line) diff --git a/developer/docs/help/guides/test/keyboard-touch-and-desktop.md b/developer/docs/help/guides/test/keyboard-touch-and-desktop.md index 9db50afbbb..5e7a9a7575 100644 --- a/developer/docs/help/guides/test/keyboard-touch-and-desktop.md +++ b/developer/docs/help/guides/test/keyboard-touch-and-desktop.md @@ -133,17 +133,3 @@ installed, across all apps. You can test multiple keyboards just by clicking **Test Keyboard on web** in each keyboard editor. -## Related articles - -Other articles on developing touch layouts: - -- [Creating a touch keyboard layout for Amharic - part - 1](../develop/creating-a-touch-keyboard-layout-for-amharic) -- [Creating a touch keyboard layout for Amharic - the nitty - gritty](../develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty) - -You can distribute your keyboard to other users by following the -instructions in this article: - -- [Distribute keyboards to Keyman - applications](../distribute/packages) diff --git a/developer/docs/help/guides/test/keyboard-touch-mobile-emulator.md b/developer/docs/help/guides/test/keyboard-touch-mobile-emulator.md index fb68b11f2b..6c7afc034d 100644 --- a/developer/docs/help/guides/test/keyboard-touch-mobile-emulator.md +++ b/developer/docs/help/guides/test/keyboard-touch-mobile-emulator.md @@ -47,15 +47,5 @@ You can now test the keyboard layout and get an idea of how it will feel on a real touch device. Rotation, or changing device types will require a page load (F5) in order to render correctly. -- [Creating a touch keyboard layout for Amharic - part - 1](../develop/creating-a-touch-keyboard-layout-for-amharic) -- [Creating a touch keyboard layout for Amharic - the nitty - gritty](../develop/creating-a-touch-keyboard-layout-for-amharic-the-nitty-gritty) - [How to test your keyboard layout — touch and desktop](keyboard-touch-and-desktop) - -You can distribute your keyboard to other users by following the -instructions in this article: - -- [Distribute keyboards to Keyman - applications](../distribute/packages) diff --git a/developer/docs/help/guides/walkthrough/00-introduction.md b/developer/docs/help/guides/walkthrough/00-introduction.md new file mode 100644 index 0000000000..0577ecef53 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/00-introduction.md @@ -0,0 +1,87 @@ +--- +title: Introduction +--- + + +
+ Introduction to the [Keyman Developer Walkthrough](.). + + [Next: Part 1 - Creating a Keyboard Project →](01-creating-keyboard-project) +
+ +## Step-by-Step + +The Step-by-Step tutorial starts with an introduction to the Keyman Developer program and instructions on installing it. Then use the link to advance to the next topic and complete the Step-by-Step section there. Continue on through all the topics, completing the Step-by-Step section and moving on to the next topic by using the link at the end of each Step-by-Step section. + +If you encounter unfamiliar terms, please consult the [glossary](glossary). + +### Introducing Keyman Developer + +Keyman Developer is a powerful tool you can use to create custom software keyboards optimized to type in any language you choose. Keyboard authors can distribute their work for desktop, web, tablet and phone, enabling global communities to quickly benefit from keyboards made for their own language. + +Keyboards created with Keyman Developer can be used on Windows, macOS, Linux, iOS, Android, and the web. + +This tutorial focuses on the Keyman Developer IDE (integrated development environment). +Currently this software is Windows-only, although the command line tools it uses can run on other platforms (such as Linux and macOS). + +### Installing Keyman Developer + +Keyman Developer is completely free to download and use. You can download it from [https://keyman.com/developer/download](https://keyman.com/developer/download). + +On the downloads page, just click the big green “Download Now” button to get the latest version of Keyman. Once you have it, run the `keymandeveloper-a.b.c.exe` file you’ve downloaded. The numbers following “keymandeveloper” indicate which version of Keyman Developer you are installing; you can also see the Keyman Developer version in the main installer window, or after installation, in the Help/About dialog. + +After installing Keyman Developer, you should be able to run it on your computer and begin creating projects immediately. + +Note that Keyman Developer is a separate app from Keyman, which is the app that lets you use any keyboard created with Keyman Developer. +In order to use the keyboard you create with Keyman Developer, you'll need to have the Keyman app installed on your computer or device. +Keyman is available on the following platforms: Windows, macOS, Linux, iOS, Android, and the web. + +The Keyman Developer icon ![Keyman Developer icon](images/keyman-developer-icon.png) is a faded version of the Keyman icon ![Keyman icon](images/keyman-icon.png). + +
+To continue the Step-by-Step tutorial move to the next page: [Part 1 - Creating a Keyboard Project](01-creating-keyboard-project) +
+ +--- + + +## Engaging with the Keyman Community and Resources + +Keyman Developer also has an active community and documentation for each major release of the app. If you need any additional help, be sure to visit the following resources for information: + +### Keyman Community Forum + +Ask questions and talk with other keyboard authors on the [Keyman Community Forum](https://community.software.sil.org/c/keyman/19) + +### Keyman online help + +[Keyman Developer Language Guide](https://help.keyman.com/developer/language/guide/) + +Information about the general structure and concepts of the Keyman language. + +[Keyman Developer Language Reference](https://help.keyman.com/developer/language/reference/) + +Reference for keywords and other components of the Keyman language. + +[Keyman Developer Training Videos](https://help.keyman.com/developer/videos) + +Videos from past Keyman Developer workshops hosted by the team. + +### Keyman Blog + +Read up on Keyman’s latest releases and patch notes on the [Keyman Blog](https://blog.keyman.com/). + +### Keyman GitHub repositories + +Keyman uses a number of [Github](https://github.com/keymanapp) repositories to store source code, keyboards, lexical models and documentation. +There is also a mechanism for reporting problems. [Keyman Bug Reports](https://github.com/keymanapp/keyman/issues) + +Report Keyman software bugs and issues here. + +> [!NOTE] +> GitHub issues are not the best place to ask for help or support questions. The Keyman community forum is a better place to ask for help with keyboard development. Think you’ve found a Keyman bug or a problem with a specific keyboard? Describe what you’ve found on the Keyman community forum and ask whether to report a bug. + +
+ [Next: Part 1 - Creating a Keyboard Project →](01-creating-keyboard-project) +
+ diff --git a/developer/docs/help/guides/walkthrough/01-creating-keyboard-project.md b/developer/docs/help/guides/walkthrough/01-creating-keyboard-project.md new file mode 100644 index 0000000000..703163964f --- /dev/null +++ b/developer/docs/help/guides/walkthrough/01-creating-keyboard-project.md @@ -0,0 +1,200 @@ +--- +title: Creating a Keyboard Project +--- + + +
+ Part 1 of the [Keyman Developer Walkthrough](.). + + [← Introduction](00-introduction)   [Part 2 - Designing a Desktop Layout →](02-designing-desktop-layout) +
+ +## Step-by-Step + +For the Dagbani keyboard, the keyboard planning has been done for you. Follow these steps to create the Dagbani keyboard project: + +- Open Keyman Developer and select `New Project` from the `Project` menu. +- The `Keyman Keyboard` option is selected by default. Click `OK`. +- A new dialog should pop up with fields for you to fill out: + +![](images/new-project-dialog.png) + +- For the Keyboard Name field, enter **Dagbani** (which will also fill in the Keyboard ID field). +- For the Description field, enter **A keyboard for typing the Dagbani language of Ghana.** +- For the Author field, you can put in your own name. Note that the Copyright and Full copyright fields are initialized. Since the copyright really belongs to SIL Global, we’ll change those fields for this tutorial. (When you create a real keyboard project, follow the advice in the [Author, Copyright and Full Copyright](#toc-author-copyright-and-full-copyright) section below.) +- In the Copyright field enter **Copyright © SIL Global** +- In the Full Copyright field enter **Copyright © 2021-2025 SIL Global** . (The date range goes from the first year that the keyboard was written to the current year. A new keyboard usually just lists a single year.) +- The Version field defaults to **1.0** and you can accept that default version number. +- The Target field defaults to **any** (meaning “any and all” of the listed target platforms). This is what will be used for the Dagbani keyboard. +- The Path field defaults to “Keyman Developer\Projects\” in the user’s “Documents” folder. +- The Keyboard ID field was initialized to **dagbani** based on the Keyboard Name entered earlier. We will keep this value. The Project filename of …**Documents\Keyman Developer\Projects\dagbani\dagbani.kpj** is displayed for information. It is the Path field plus the keyboard’s project folder (which uses the Keyboard ID field as its name) plus the keyboard project file (which uses the Keyboard ID field as the name with the .kpj file type). +- Select the `Add` button to add a BCP 47 language tag for the language. In the dialog that comes up, enter **dag** in the `Language tag` field and verify that the Language name field shows as **Dagbani**. +- Select `OK` to close the `Select BCP 47 tag` dialog. +- Select `OK` to close the `New Basic Keyboard Project` dialog. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 2 - Designing a Desktop Layout](02-designing-desktop-layout) +
+--- + +## Planning a Keyboard + +The first step is identifying the language or languages your keyboard will cover. Some keyboards support multiple different languages within the same region. This approach, however, has some significant drawbacks: + +- it is difficult to optimize a keyboard for multiple languages since a rarely used character for one language may be a common character for another. +- it is harder for users to find the keyboard since the name of the keyboard may not relate to the particular language they are researching. +- it is more difficult for users to select the correct language for during installation, particularly if a keyboard handles many languages. This is particularly important for lexical models for predictive text, as a separate model is needed for each language. + +Furthermore, having a keyboard specifically designed for a single language may help with community acceptance. + +If you do need to provide keyboard support for a number of languages in a region, consider planning the keyboards together, so that you can make them as similar as possible, but then make a separate keyboard for each language. + +Once you have figured out what language your keyboard will support, you will need to familiarize yourself with which characters (including punctuation) are used to write it. You will need to determine what key or key combinations are needed to produce these characters. There may be major benefits in keeping as close as possible to the standard layout for a language of wider communication. On the other hand, repurposing a key from the standard layout may make it easier to type the target language. + +## Understanding User Needs + +Once you understand what is needed to support the language, you should seek to understand the needs of its speakers. +A few good questions to start with are: + +- Who will use this keyboard? +- What devices will they use it on? +- What are the most important keys on the keyboard? +- What have people been using to type instead? + +Understanding the users is the key to designing an effective keyboard. Is it intended for fluent or basic speakers of the language? Are the users familiar with common keyboards already? Have they already learned a certain keyboard format or style of typing? (If you plan to be the primary user of this keyboard, think about how others may want to use it if it turns into a more valuable tool than you anticipated.) + +Be sure to look for keyboards that may exist for the language(s) you want to support before beginning work. Although they may not be perfect solutions, if there is a keyboard that your language’s speakers already have and are familiar with, building on its foundation can significantly save time. You might discover a keyboard that already does exactly what you need! + +Once you’ve planned the basic premise of your keyboard, you can open Keyman Developer and start filling out your project info. + +## Creating a Keyboard Project + +Open Keyman Developer and select `New Project` from the `Project` menu. + +The `Keyman Keyboard` option is selected by default. Click `OK`. A new dialogue should pop up with fields for you to fill out. + +The information that you enter will initialize several files in your keyboard project. +Making sure that the information is correct at the beginning will avoid having to correct your files later. + +### Keyboard Name and Keyboard ID + +This is the name of your keyboard project. + +Make sure to name your keyboards intuitively. A good standard starts with the name of the language or language group you are developing for, followed by any necessary identifiers such as `Phonetic`, `Mnemonic`, `Latin`, `QWERTY`, etc. in case there are multiple keyboards available for the same language. +Do not use the word “keyboard” in the name. Adding “keyboard” to the keyboard name is redundant and will not help people find it. Similarly, don’t include “Unicode” in the name. + +If you decide to change the name of the keyboard, you’ll need to change it in a number of files: `HISTORY.md`, `README.md`, `readme.htm`, and `welcome.htm`, as well as the `.kmn` and `.kps` files. + +Note that the `Keyboard ID` (near the bottom of the dialog) fills in automatically with the name you choose, but formatted like `keyboard_name` (changing uppercase characters to lowercase, and non-English characters and spaces to underscore). +You can modify the value in this field, though you are limited to the characters a-z, the numbers 0-9 and underscore. +This value will be used as the base filename of many of your Keyman files. + +> [!NOTE] +> If you decide to change the keyboard ID, you’ll need to change most of the files in the project. This is best done using Keyman Developer’s `Clone local project` feature. +> • From the `Project` menu, select `New Project` then `Clone local project`. +> • Use the `Browse` button to navigate to the `.kpj` file of your existing project. +> • Specify a new `project ID` (and adjust `Destination path` if desired), then select `OK`. + +### Description + +This brief description of your keyboard is included in all of your information files. +Try to keep this short but informative, as this is what people will see when searching for your keyboard on the keyman.com website. +It may be useful to include alternate language names, the script (Latin, Devanagari, etc) +if the language is written in more than one script, the region where it is used, or other details about the keyboard. + +The description field can use [Markdown](https://www.markdownguide.org/cheat-sheet/) for basic formatting and links. + +The description is added to `README.md` and the package `.kps` file. + +### Author, Copyright, and Full Copyright + +Enter your name in the `Author` field. +Note that the `Copyright` and `Full Copyright` fields will automatically populate with your name as well. +If you are developing keyboards that will be copyrighted by an organization, make sure to edit the Copyright fields accordingly. +The Full Copyright field has the date as well as the copyright holder. + +The name used in the Copyright fields must be the real name of an individual or of an organization. +Copyright cannot be assigned to a pseudonym. + +The short copyright message is added to `README.md`, `welcome.htm`, `readme.htm`, package `.kps` details, and the [`©right` keyboard system store](https://help.keyman.com/developer/language/reference/copyright) in the `.kmn` file. +The full copyright message is added to `LICENSE.md`. + +### Languages + +This table displays the [BCP 47](../../reference/bcp-47) tag (or tags) associated with your keyboard. +A BCP 47 tag identifies a language and will help users find your keyboard when they search for their language. +If you don’t know what your language’s tag is, you can search for its name and find the corresponding tag in the [IANA Language Subtag Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry), which contains all existing BCP 47 tags, the [Glottolog](https://glottolog.org/glottolog/language) (under the ISO-639-3 column), or the [SIL Ethnologue](https://www.ethnologue.com/). + +The SIL Ethnologue is the most user-friendly option of the three, if you are unfamiliar with language tags. + +In addition to your basic BCP 47 tag, you can add +[Script](../../reference/bcp-47#toc-the-script-subtag) and +[Region](../../reference/bcp-47#toc-the-region-subtag) subtags. +However, you should always use the simplest possible BCP 47 tag to identify your language. +Only add Script and Region tags if your keyboard is for a script or region that differs from the most commonly used form of the language. + +Language information is added to `README.md` and in the package `.kps` file, in the Keyboards section. + +### Version + +The keyboard version number allows Keyman to tell which of two copies of a keyboard is newer. This allows Keyman to offer users updated versions of keyboards. + +The version number consists of two or three integer numbers separated by periods. Don’t use more than three numbers. Don’t use leading zeros. If the third number is absent, it is considered to be zero. Version numbers are compared number by number, so `2.51` is a higher version number than `2.6.1` (since 51 is greater than 6). + +New keyboards usually start with version `1.0` (which is equivalent to `1.0.0`). +Generally the first number is incremented for major changes to the keyboard, +the second for minor changes, and the third for corrections or bug fixes (this is known as [semantic versioning](https://semver.org); note that Keyman keyboard versions do not allow additional labels). + +The most important point is that the new version number be greater than the existing one (as noted above). + +The version number appears in the `HISTORY.md` file and the `.kmn` file in the [`&keyboardversion` keyboard system store](https://help.keyman.com/developer/language/reference/keyboardversion). +It should be updated in both places whenever you distribute a new version of the keyboard. + +### Targets + +This is where you choose which platforms that your keyboard will be supported on. +As you can see, Keyman offers support for a wide variety of platforms. +Although you can pick and choose what formats you wish to develop for, `any` is the best option, because it will automatically generate files to support all formats that Keyman offers. +If you select `any`, you do not need to (and should not) choose any other options. + +It is best practice to support as many devices as possible when creating your keyboard, because it is hard to predict who will use your keyboard in the future. By making your keyboard as accessible as possible, you can help even more people. + +If you decide not to include a touch layout, untick the `any` option and select `desktop` and `web` which will allow the keyboard to be used on a web page as well as on Linux, macOS and Windows (the three `desktop` platforms). If you later add a touch layout, you can reverse this process and go back to selecting just `any` in the [`&targets` keyboard system store](https://help.keyman.com/developer/language/reference/targets). + +### Path + +This is location on your computer where your keyboard project and all associated files will be stored. +By default, your projects will be stored in a folder with the same name as the `Keyboard ID` value +and that folder will be placed under the keyboard author's `Documents\Keyman Developer\Projects\` folder. + +It’s a good idea to let Keyman handle naming your files, since it uses good naming convention and will make things easier to find in the future. However, if you need to place the project somewhere else, you can click the `Browse...` button beside this field and navigate to the desired folder. + +Once you have filled out all of the fields, +Keyman Developer will create your project and open it in a new window with your project’s `.kpj` (Keyman project) file displayed. +You can read more about the `.kpj` file type in the [official Keyman documentation](../../reference/file-types/kpj). + +## Basing a new Keyboard Project on an existing one + +Keyman has a well-maintained [Github repository](https://github.com/keymanapp/keyboards) for keyboards that have been published by the team or community members. +You can download a keyboard from the repository and use it as the basis for your own project. +The easiest way to do this is with the `Clone project from Keyman Cloud` feature of Keyman Developer (version 18 and later). + +Open Keyman Developer and navigate to `Project` > `New Project` in the top menu bar. + +Select the `Clone project from Keyman Cloud` option, then `OK`. A new dialog appears where you can: + +- search for a keyboard (by keyboard name, language, script, country, BCP 47 tag) +- select a keyboard from the search results +- specify a New project ID +- optionally move external files into the new project folder +- optionally navigate to a different destination folder + +When ready, select `OK` to download the files, adjust the filenames and open the new project in Keyman Developer. + +## Conclusion + +Now that you have your project set up, continue to the next section of the tutorial to start developing your first keyboard layout. + +
+ [← Introduction](00-introduction)   [Part 2 - Designing a Desktop Layout →](02-designing-desktop-layout) +
diff --git a/developer/docs/help/guides/walkthrough/02-designing-desktop-layout.md b/developer/docs/help/guides/walkthrough/02-designing-desktop-layout.md new file mode 100644 index 0000000000..b92794db32 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/02-designing-desktop-layout.md @@ -0,0 +1,149 @@ +--- +title: Designing a Desktop Layout +--- + + +
+Part 2 of the [Keyman Developer Walkthrough](.). + +[← Part 1 - Creating a Keyboard Project](01-creating-keyboard-project)   [Part 3 - Creating a Desktop Layout →](03-creating-desktop-layout) +
+ +## Step-by-Step + +Dagbani uses the characters **ɛ ɔ ŋ ɣ ʒ** and the corresponding capital letters **Ɛ Ɔ Ŋ Ɣ Ʒ**. +Rather than try to assign each of these characters to a key on the physical keyboard, +we will use a pair of keys to produce each of these characters. +We’ll start with the default QWERTY layout and add rules so that typing ; followed by e will produce “ɛ”, +; followed by o will produce “ɔ”, etc. + +This Step-by-Step tutorial won’t be using the visual layout features of Keyman Developer for creating the desktop keyboard. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 3 - Creating a Desktop Layout](03-creating-desktop-layout) +
+ +--- + +## Defining a List of Keys + +After you have gathered some basic information about the language for which you are creating a keyboard, +along with the needs of the people who will be using it, +the next step is to figure out what format will suit the needs of your keyboard’s users and be most familiar to them. + +Keyman is available across [many different platforms](https://help.keyman.com/products/), so consider whether you need to design keyboard formats for computer keyboards, phones, or tablets. +Keyman makes it easy to keep designs consistent across these types, but it is also possible to design each layout individually. + +Make a list of all of the characters that your language uses in its written form. For example, the Dagbani language uses the following characters, in addition to a standard A-Z alphabet: + +| Name | Character | +|--------|-------------| +| Open e | ɛ Ɛ | +| Open o | ɔ Ɔ | +| Eng | ŋ Ŋ | +| Gamma | ɣ Ɣ | +| Ezh | ʒ Ʒ | + + +This is a simple example. Some languages may have extensive punctuation marks, special glyphs, or use a non-Latin alphabet. +Be thorough in your list so that you are not missing any keys when you design your keyboard. + +Note that Unicode contains some characters that are quite similar, so verify the Unicode values you are using. +For example, this example uses `ɔ` (`U+0254`) "open o", not `ↄ` (`U+2184`) "reversed c". + +## Creating a Visual Layout + +Once you know what keys your keyboard will need, it is time to determine how to arrange them. +The best way to do this varies widely depending on your language. +If users have been typing with a certain keyboard layout and are familiar with it, that might provide a good starting point. +Research existing keyboard layouts and build off of them where possible. +You may want to use the keyboard layout common in the area (QWERTY in English-speaking areas, AZERTY in French-speaking areas, etc.) as a basis for your keyboard. + +For visual mapping, this can be done with tools as rudimentary as a pen and paper, but Keyman Developer also offers a handy visual keyboard for design purposes. + +Navigate to your `.kpj` file, go to the `Keyboards` tab, and open your `.kmn` file. This is where your keyboard’s information lies, as well as the code that makes it work. + +You can read more about the `.kmn` file type in the [official Keyman documentation](../../reference/file-types/kmn). + +Inside your `.kmn` file, select the `Layout` tab on the left. +For a new project, the `Design` tab (at the bottom) should already be selected. +This is a visual representation of your desktop keyboard. +Note that once you add rules using the `Code` tab (as, for example, in the Dagbani keyboard developed in the Step-by-Step tutorial), +Keyman Developer no longer offers the `Design` tab option. + +By default, Keyman Developer uses a QWERTY layout, but it is very easy to remap this. +If you are using a non-QWERTY base keyboard layout, select each key and press the corresponding key on your keyboard. +This will automatically change the keyboard code to type the key you have selected. + +To access the characters needed for your language, you can paste the Unicode characters you need into the two fields at the bottom. +`Unicode Character Value(s)` is for the Unicode value (for example, `U+0061`) of the character you would like the keyboard to type, +while `Output character(s)` is for the character the keyboard will produce (for example, `a`). +Typing in either field will automatically populate the other one with matching information, so it does not matter which one you use. + +If a key needs to produce multiple characters (for example, a key that produces `ch`), you can place multiple characters in the `Output character(s)` field. + +After some research, you may find that your language has more characters than there are keys on the keyboard. +This is especially true of languages with many glyphs, combined characters, or diacritical marks on letters. +In this case, it is especially helpful to follow a default keyboard layout for your base design, +and plan out special keystrokes so users can type the characters that are not immediately available on the keyboard. +Try to ensure that the most essential keys (usually the ones used to type the alphabet) are available before worrying about adding less frequent characters. + +## Planning Keystrokes + +Once you know what you want your keyboard layout to look like, you can begin planning what keystrokes will be needed. +You can specify rules so that Keyman will transform typed keystroke combinations into the desired characters. + +For example, you can use the keystrokes `'` + `e` to produce the character `é` rather than dedicating a separate key to `é`. + +When choosing keys to use for characters you are adding to your keyboard, be careful not to block the normal function of those keys. +In the above example, consider whether there would be a need to allow someone to type an actual apostrophe. + +To easily plan keystrokes, you can reference the list you made of the special characters needed for your language. Disregarding the letters and symbols already included in the base layout you designed, how many more do you need to fit onto your keyboard? You can utilize the number row, punctuation characters, deadkeys, and the Right-Alt, Shift, or Shift+Right-Alt modifier keys in your layout. Remember to make them as intuitive as possible for users. If the key combination is too complex, it will slow users down significantly when attempting to type. + +Remember to include capital letters in your list! Keyman treats these separately, so you will have to code uppercase and lowercase letters separately. + +Here’s an example of how to list your keystrokes. (This can also be reused when you document your keyboard’s layout later!) If you want to be thorough, you can also list the Unicode values for each character to avoid any confusion about which character is used. + +| Base | Modifier | Result | +|------|----------|--------| +| a | ^ | â | +| e | ^ | ê | +| i | ^ | î | +| o | ^ | ô | +| u | ^ | û | + +Once you have planned the visual layout of your keyboard and determined how to assign the rest of the keys on the keyboard, it’s time to begin coding. +If your layout is simple enough that you do not need to program additional keys, you do not need to worry as much about the next section. +In some cases, using Keyman’s visual editor is enough for a desktop keyboard. + +> [!NOTE] +> Once you begin adding multi-part rules, the keyboard becomes too complex to modify with the visual layout tools, so it is best to do any visual layout work first using the `Design` tab, then add the additional rules using the `Code` tab. + +### Deadkeys + +The Step-by-Step tutorial uses `;` plus another key (`e E o O n N g G z Z`) to produce the ten additional characters (`ɛ Ɛ ɔ Ɔ ŋ Ŋ ɣ Ɣ ʒ Ʒ`). +When the “;” is typed it appears on the screen. +When one of the ten keys is typed directly after the “;” then the “;” is replaced by the corresponding additional characters. + +In contrast to this approach, the “deadkey” alternative could be used. +A deadkey produces no display when typed, but modifies the keystroke that follows it. +To use a deadkey approach for the Dagbani keyboard, we would use a rule to convert the `;` keystroke into a deadkey, which will not display on the screen, but will then be used to create the appropriate additional character when one of the ten characters is typed. +Some European language keyboards (French, for example) use deadkeys, so users in French-speaking countries may already be familiar with their use. + +While useful in some situations, deadkeys can also confuse users. +In this example, when the `;` key is pressed, it will not produce anything. +If you include deadkeys in your keyboard, be sure to document them well so that users understand what is happening when they type them. + +For more information, see the Keyman documentation for the [`deadkey()` statement](https://help.keyman.com/developer/language/reference/deadkey). + +### Reassigning keys + +But consider the Dagbani example again. +Suppose we don’t want to have to type two keys to obtain each of these additional characters (as if they were somehow inferior to the other twenty-six). +We could choose to design the keyboard so that typing `[ { ] } - _ = + \ |` will produce `ɛ Ɛ ɔ Ɔ ŋ Ŋ ɣ Ɣ ʒ Ʒ`, respectively. +That could be done with the `Design` mode using the visual layout tools, or by adding rules. +We would then want to add rules to allow the user to type the characters that were on the ten keys that we repurposed to type the additional characters, for example type the `;` key then the `[` key to get an actual `[` character. + +
+[← Part 1 - Creating a Keyboard Project](01-creating-keyboard-project)   [Part 3 - Creating a Desktop Layout →](03-creating-desktop-layout) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/03-creating-desktop-layout.md b/developer/docs/help/guides/walkthrough/03-creating-desktop-layout.md new file mode 100644 index 0000000000..f7b1c6cc63 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/03-creating-desktop-layout.md @@ -0,0 +1,339 @@ +--- +title: Creating a Desktop Layout +--- + + +
+Part 3 of the [Keyman Developer Walkthrough](.). + +[← Part 2 - Designing a Desktop Layout](02-designing-desktop-layout)   [Part 4 - Using the Debugger →](04-using-debugger) +
+ +## Step-by-Step + +On the “Creating a Keyboard Project” page, the **dagbani** keyboard project was created. +Keyman Developer displays a tab for the project file `dagbani.kpj` (just below the menu and toolbar). +There are tabs across the bottom for different steps in the process. + +![](images/keyboards-tab.png) + +- Click on the `Keyboards` tab at the bottom of the Keyman Developer window. +- Then click on the `dagbani.kmn` filename. This will open the dagbani.kmn file (as a second tab along the top, just below the menu and the toolbar) and display a set of tabs along the left side of the Keyman Developer window. Initially the `Details` tab is displayed and you can see some of the items you entered when creating the project. +- Click on the `Layout` tab from the set of tabs on the left. +- By default the `Design` view is shown and you can use the Character Map to assign characters to various keys: + +![](images/code-tab.png) + +- For this tutorial, however, we’re going to use the `Code` view. At the bottom of the Layout pane, click on the `Code` tab and the Keyman code is displayed: + +```keyman +store(&VERSION) '10.0' +store(&NAME) 'Dagbani' +store(©RIGHT) 'Copyright © SIL Global' +store(&KEYBOARDVERSION) '1.0' +store(&TARGETS) 'any' +store(&BITMAP) 'dagbani.ico' +store(&VISUALKEYBOARD) 'dagbani.kvks' +store(&LAYOUTFILE) 'dagbani.keyman-touch-layout' + +begin Unicode > use(main) + +group(main) using keys +``` + +- Choose one of the following two options (which produce equivalent results). You can type the lines or copy and paste from the tutorial. The first option lists a separate rule for each character. This may make it easier to understand what the rules do. The second option makes use of features in the Keyman language that allow more compact rules to be written. +- Option 1: Add the following lines after the `group(main) using keys` line. Each line has the code to generate one character based on “;” and a base key. + +```keyman +";" + "e" > "ɛ" +";" + "E" > "Ɛ" +";" + "o" > "ɔ" +";" + "O" > "Ɔ" +";" + "n" > "ŋ" +";" + "N" > "Ŋ" +";" + "g" > "ɣ" +";" + "G" > "Ɣ" +";" + "z" > "ʒ" +";" + "Z" > "Ʒ" +``` + +- Option 2: Add the following lines after the `group(main) using keys` line. The base keys are placed in one `store` (storage area) and the characters to produce are placed in a second store. The third line has a single rule that does the equivalent of the ten rules listed above. + +```keyman +store(basekey) "eongzEONGZ" +store(output_char) "ɛɔŋɣʒƐƆŊƔƷ" +";" + any(basekey) > index(output_char,2) +``` + +- Select the `Icon` tab on the left side of the window. This icon is displayed by the operating system when the keyboard is active. By default Keyman Developer creates a short abbreviation of the keyboard name (”DAG” in this case). You can use the color palette at the right to select different colors and click on squares in the grid to change their color. For this tutorial we will accept the default. +- Select the `On-Screen` tab on the left. This is the keyboard image that is displayed when the uses asks for help. As you can see it’s currently blank, which is not so helpful. +- Tick the `Auto-fill from underlying layout` checkbox at the bottom of the keyboard display. +- Then select the `Fill from layout` button at the top. Keyman Developer fills in the keyboard. Since we didn’t modify any keys, the display shows up as a normal QWERTY keyboard. This is still useful, since the on-screen keyboard can also be used to enter text and typing on a blank keyboard is difficult! +- Select the `Build` tab on the left, then the `Compile Keyboard` button. (Alternatively you can use the `Keyboard` menu, `Compile Keyboard` menu item to compile the keyboard. Or you can use the F7 function key as a shortcut.) +- You should see messages at the bottom indicating `dagbani.kmn built successfully`. If this is not the case, you’ll need to examine the error messages to see what the error is and correct it. + +## Interpreting Errors + +When compiling your Keyman code, Keyman Developer will report any errors, warnings and hints in the box at the bottom of the window. The message will give a short description of what the compiler found was wrong along with the line number of where the problem was detected. The error, warning or hint has an identifier (“KM02033” for example). This identifier is a link to a more detailed description. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 4 - Using the Debugger](04-using-debugger) +
+ +--- + +## Using the Visual Editor + +At the end of the [Designing a Desktop Layout](02-designing-desktop-layout) topic, an alternative Dagbani keyboard design was mentioned. +In that approach, typing the +[ { ] } - _ = + \ | +keys would produce `ɛ Ɛ ɔ Ɔ ŋ Ŋ ɣ Ɣ ʒ Ʒ`, respectively. + +If you wanted to implement such a design, Keyman Developer's Visual Editor would be very useful. +When the `Layout` tab is selected on the left, Keyman Developer starts off in `Design` mode, displaying the keyboard. +If the Character Map is not displayed on the right-hand side of the window, +you can use the `View` menu and the `Character Map` menu item to show or hide it. +(Shift+Ctrl+C is a keyboard shortcut to accomplish the same thing.) + +![](images/charmap.png) + +To assign the `ɛ` character to the `[` key, locate the desired character in the Character Map and drag it to the desired key. +If you click on that key, you’ll see it change color and the information about it will be displayed below the keyboard layout. + +![](images/unicode-character-value.png) + +On the key cap, this shows: + +- `[` the default value from the QWERTY layout +- `ɛ` the character that the key will produce + +Below the key cap, there are two edit fields which allow you to change the character that the key will product: + +- `U+025B` the Unicode value(s) that the key will produce +- `ɛ` the character(s) that the key will produce (the equivalent of the Unicode value) + +These two edit fields are linked. If you change one, the other will change. + +Clicking on the `Code` tab at the bottom of the window displays the code equivalent of the work in the visual editor: + +```keyman +group(main) using keys ++ [K_LBRKT] > 'ɛ' +``` + +Note that `[K_LBRKT]` is how Keyman Developer refers to the left square bracket key (the key just to the right of the “P” key on a QWERTY keyboard). +It also accepts `'['` or `"["` as equivalent ways to refer to that key. + +If you were to continue this example, you would drag the `ɔ` character to the `]` key and repeat the process for the other three lower case characters. Then you would click on one of the two “Shift” keys and repeat the process for the five upper case characters. + +## Understanding Keyman Code + +Keyman’s Visual Editor (the `Design` mode of the `Layout` tab) is helpful in assigning characters to keys in a consistent manner. For a simple keyboard, it may be all that you need. It’s likely, however, that you’ll need to use the `Code` tab to provide the logic needed for your keyboard. + +When you begin an new project (using the “Project” menu, “New Project” menu item), Keyman Developer initializes your `.kmn` file. +With the `Layout` tab on the left selected, you will see two small tabs at the bottom of the window: the `Design` tab and the `Code` tab. +When you switch to the `Code` tab, you should see something like the following. (This example is from the Step-by-Step tutorial.) + +```keyman +store(&VERSION) '10.0' +store(&NAME) 'Dagbani' +store(©RIGHT) 'Copyright © SIL Global' +store(&KEYBOARDVERSION) '1.0' +store(&TARGETS) 'any' +store(&BITMAP) 'dagbani.ico' +store(&VISUALKEYBOARD) 'dagbani.kvks' +store(&LAYOUTFILE) 'dagbani.keyman-touch-layout' + +begin Unicode > use(main) + +group(main) using keys +``` + +The `store()` statements at the top are called the “header” of your file. +This is where the important information about your keyboard is stored. + +A summary of the elements of the Keyman header can be found in the [language guide](https://help.keyman.com/developer/language/guide/headers) and detailed information is in the official Keyman documentation: + +- [&version](https://help.keyman.com/developer/language/reference/version) +- [&name](https://help.keyman.com/developer/language/reference/name) +- [©right](https://help.keyman.com/developer/language/reference/copyright) +- [&keyboardversion](https://help.keyman.com/developer/language/reference/keyboardversion) +- [&targets](https://help.keyman.com/developer/language/reference/targets) +- [&bitmap](https://help.keyman.com/developer/language/reference/bitmap) +- [&visualkeyboard](https://help.keyman.com/developer/language/reference/visualkeyboard) +- [&layoutfile](https://help.keyman.com/developer/language/reference/layoutfile) +- [&mnemoniclayout](https://help.keyman.com/developer/language/reference/mnemoniclayout) + + +## Writing Keyman Rules + +The body of your code begins after the header. This is where the bulk of your keyboard’s functionality will be. + +```keyman +begin Unicode > use (main) +``` + +The preceeding line tells Keyman + +- to use Unicode encoding when typing characters, and +- to look for the rules determining what characters should be produced in `group(main)` . + +```keyman +group(main) using keys +``` + +is the default group for defining keyboard rules. This is where we will write code to implement the keystrokes you decided to use. + +For more advanced uses of the `begin` rule, like defining different rulesets based on typing context, see the [official Keyman documentation](https://help.keyman.com/developer/language/reference/begin). + + +There are a few key terms that you must know when writing rules: + +**Context** + +The context specifies the conditions that will trigger a rule. +If the character(s) prior to the cursor match the context of a rule, the rule will be processed by Keyman. + +**Key** + +The key specifies which keystroke the rule will act upon. +For more information on keys and keystrokes, read the [official Keyman documentation](https://help.keyman.com/developer/language/guide/virtual-keys). + +**Output** + +The output determines which characters are produced by a rule. When a rule is processed, Keyman will replace the context with the output. + +The Context (which may be empty) is separated from the Key by `+`. + +The Key is separated from the Output by `>`. + +You can include comments in your Keyman code by typing a plain `c` followed by a space then any text you like afterwards. (If you want the letter “c”, you must surround in in quotes like `"c"`.) This is a good way to document your code and make things easier to read later, both for yourself and others. Comments can be made at the end of a line (with a space before the `c` as well as after) or be on their own line. Any text that follows the `c` through the end of the line will be ignored when the keyboard is compiled. + +Writing rules in Keyman is very straightforward for simple key substitutions. Suppose we want circumflex plus “a” to produce the character “â”. The Keyman code is actually very similar: + +`"^" + "a" > "â"` + +In this example, the **context** is `^`, the **key** is `a`, and the **output** is `â`. +Whenever Keyman finds the context (`^`) prior to the cursor and the current keystroke is `a`, it will replace the context (and the typed character) with `â`. + +Characters written into Keyman code should always be surrounded by single quotes (`' '`) or double quotes (`" "`). +Either pair will work (as long as they match). +It is also possible to use the Unicode values of characters directly in the code. +These are never written with quotes around them. + +The previous line of code, when rewritten to use Unicode values, looks like this: + +```keyman +U+005E + U+0061 > U+00E2 +``` + +While less readable to a human, using Unicode values for uncommon or easily confused characters is often a good idea. + +It's possible to use a comment to provide both the Unicode value and the character itself, for example rewriting the above line as: + +```keyman +"^" + "a" > U+00E2 c â +``` + +At a glance, this tells you that a circumflex (`^`) combined with `a` will produce the Unicode character `â` (whose value is U+00E2). +Including a comment at the end of each rule that shows the output character will make reviewing your code significantly easier while still being extremely clear about which characters are used. + +Below is an example of useful comments in the SIL EL Ethiopic Latin keyboard explaining a set of rules and each rule’s output: + +![](images/characters-in-comments.png) + +Some Keyman rules have no context, that is, a context that is empty. The following line: + +```keyman ++ "e" > U+025B c ɛ +``` + +is an example of the most basic rule possible. You may have noticed lines like these in your code after using the `Design` tab to edit your keyboard. + +Note that rules created when using the `Design` tab use [virtual key codes](/developer/language/guide/virtual-keys#common-virtual-key-codes) rather than the corresponding characters. +This does not matter unless you are writing a [mnemonic layout](https://help.keyman.com/developer/language/reference/mnemoniclayout) keyboard. Keyman keyboards are positional -- the opposite of mnemonic -- by default, so unless you specify a mnemonic layout in your header, the following two lines of code will produce the same output: + +```keyman ++ "e" > U+025B ++ [K_E] > U+025B +``` + +### Stores + +Stores can be used to write concise rules that apply to a set of characters. +For example, in the following code, the store called `basekeys` contains the keys for five vowels. +A second group called `vowels_acute` contains the same five vowels (in corresponding order) with an acute accent. +And the single rule combines the apostrophe with a base vowel to produce a vowel with an acute accent. + +```keyman +store(basekeys) "aeiou" +store(vowels_acute) "áéíóú" +"'" + any(basekeys) > index(vowels_acute,2) +``` + +Thus the code above is equivalent to the following five rules: + +```keyman +"'" + "a" > "á" +"'" + "e" > "é" +"'" + "i" > "í" +"'" + "o" > "ó" +"'" + "u" > "ú" +``` + +You can read more about the `store`, `index` and `any` keywords in the [Keyman language documentation](https://help.keyman.com/developer/language/reference/). + +### Deadkeys + +At the end of the previous topic, an example was given of using the ; key as a “deadkey”. Typing the deadkey produces no output, but it potentially changes the output of the following key. Changing the first two rules from the Step-by-Step example to treat the ; as a deadkey, would result in: + +```keyman ++ ";" > dk(1) c Define ";" as a deadkey +dk(1) + "e" > "ɛ" c deadkey followed by "e" produces "ɛ" +dk(1) + "E" > "Ɛ" c deadkey followed by "E" produces "Ɛ" +``` + +If you follow the instructions for the Debugger, you’ll find that the keystroke log is the same, but in the right-hand side of the display, the “;” is replaced by an indication of the deadkey. + +### Groups + +Groups can be used in several ways to make your code simpler and more efficient. There are two types of groups: + +- groups that process only the context +- groups that process the context and the keystrokes + +You can read more about their uses in the [Keyman documentation](/developer/language/guide/groups). + +## Creating an On-Screen Keyboard Layout + +An on-screen keyboard (OSK) is a graphic representation of the desktop layout. It is displayed on the computer screen to show where keys are located. In can also be used to input text by clicking on the keys. + +Select the `On-Screen` tab on the left to display the layout (one layer at a time). +You can manually create the OSK by clicking on a key and typing the character that should be displayed there. + +It is also possible to create an on-screen layout automatically based on what you have designed and coded on the Layout tab. +(If you have manually created your on-screen layout information, you should be aware that the following automatic process will overwrite what you have created.) + +- Any key that you don’t reassign will have the function of the US English keyboard. If you are relying on this in your keyboard, you should tick the `Auto-fill underlying layout` box below the keyboard image. +- Select the `Fill from layout` button above the keyboard image +- Check the results. + +The On-Screen Keyboard editor looks very similar to the `Design` mode of the `Layout` tab. Most of the time, the key caps will be the same as in the `Design` mode of the `Layout` tab, but sometimes it might be helpful to display something different than what is actually produced. If, for example, the character being produced is not visible, such as a no-break space or a right-to-left mark, it might be helpful to display `NBSP` or `RTL` or some symbol to remind the user what the key produces. + +## Exporting an On-Screen Keyboard Layout + +One way to document a keyboard layout is to use images of the keyboard showing the different layers: default layer, Shift layer, Right-Alt layer, etc. +Keyman Developer provides a way to export such images from the `On-Screen` tab. + +Once you have the layout (created either manually or automatically), you can use the `Export` button. +Then complete the information needed: + +- Navigate to the folder where you want to create the files +- Supply a base filename +- For the `Save as type` field, select `Image (*.png)` +- Select `Save` +- In the `Output Bitmap Parameters` dialog, select `One file per shift state`, `Output Unicode keyboards`, and adjust the width of the image as needed, then select `OK`. Keyman Developer will create one or more files using the base filename plus letters to indicate the shift state plus `.png`. You can reference these files in your welcome.htm file. + +
+[← Part 2 - Designing a Desktop Layout](02-designing-desktop-layout)   [Part 4 - Using the Debugger →](04-using-debugger) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/04-using-debugger.md b/developer/docs/help/guides/walkthrough/04-using-debugger.md new file mode 100644 index 0000000000..42b8de61c4 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/04-using-debugger.md @@ -0,0 +1,35 @@ +--- +title: Using the Debugger +--- + + +
+Part 4 of the [Keyman Developer Walkthrough](.). + +[← Part 3 - Creating a Desktop Layout](03-creating-desktop-layout)   [Part 5 - Designing a Touch Layout →](05-designing-touch-layout) +
+ +## Step-by-Step + +- From the `Debug` menu, select the `Start Debugging` menu item. Some extra fields will be shown. +- Type ;. The Keystroke log will show `;`. The display to the right has two sections. The upper section shows the characters displayed on the screen. The lower section shows a table of characters and their Unicode values. Here the upper section will show `;` and the lower section will show `;` and `U+003B`. (U+003B is the Unicode value for “;”.) +- Type e. The Keystroke log will show `;` and `E`. The display to the right will show `ɛ` in the upper section and `ɛ` and `U+025B` in the lower section. (U+025B is the Unicode value for “ɛ”.) +- Type ; then E. The Keystroke log will show `;` `E` `;` `Shift+E`. The display to the right will show `ɛƐ` in the upper section and `ɛ` and `U+025B` then `Ɛ` and `U+0190` in the lower section. + +![](images/debugger-output.png) + +- From the `Debug` menu, select the `Stop Debugger` menu item. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 5 - Designing a Touch Layout](05-designing-touch-layout) +
+ +--- + +## Running the Debugger + +See the [debugger documentation](../../context/debug) for more information on running the debugger. + +
+[← Part 3 - Creating a Desktop Layout](03-creating-desktop-layout)   [Part 5 - Designing a Touch Layout →](05-designing-touch-layout) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/05-designing-touch-layout.md b/developer/docs/help/guides/walkthrough/05-designing-touch-layout.md new file mode 100644 index 0000000000..acc2f9d6d5 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/05-designing-touch-layout.md @@ -0,0 +1,62 @@ +--- +title: Designing a Touch Layout +--- + + +
+Part 5 of the [Keyman Developer Walkthrough](.). + +[← Part 4 - Using the Debugger](04-using-debugger)   [Next: Part 6 - Creating a Touch Layout →](06-creating-touch-layout) +
+ +## Step-by-Step + +In the Dagbani keyboard, `;e` was selected as the way to generate the character `ɛ` , but having to type a `;` on a touch screen followed by `e` to get the `ɛ` character would be tedious. It is preferable to assign `ɛ` as a longpress key on the `e` key. + +For the Step-by-Step tutorial, the design decisions have been made for you. We will be adding ten longpress keys to the default touch layout. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 6 - Creating a Touch Layout](06-creating-touch-layout) +
+ +--- + +## Creating a Basic Visual Layout + +Adding a touch keyboard layout to your keyboard project allows a user to input text on touch devices, such as tablets and phones. + +A desktop keyboard is dependent on the physical keyboard. With a touch layout, you will be displaying the keys on the device for the user to see and interact with. + +There is some flexibility in arranging keys, though adding too many keys to a row or too many rows to a layout will make the keyboard difficult to use. Additionally, there are options for activating a key: + +- touch, that is touch and release the key +- longpress, that is touch and hold the key, then select a character from a popup menu +- flick, that is touch the key and slide in one of eight directions +- mulitap, that is rapidly touch and release the key: one tap produces the base key, two taps produces the first multi-tap key, three produces the second multi-tap key, etc. + +## Planning Keystrokes + +You’ll want to plan your touch layout just as you did for the desktop (physical keyboard) layout. There is some value in making the touch layout similar to the desktop layout, but the primary concern is making it easy to use. + +Another possibility, if a small number of additional characters are needed, is to give each of them their own keys. This is possible since a touch layout is displayed on the screen. + +If you use Keyman Developer’s New Project feature, a touch layout is added automatically. + +## Using the desktop layout as a basis for the touch layout + +There are advantages to basing the touch layout on the desktop layout. +Users who switch between the two may benefit from the similarity. +In addition, your touch layout may be able to take advantage of the logic in the desktop layout code you’ve already created. +Specifically, if the `ID` field for a key in the touch layout begins with `K_` then Keyman treats the key as the same as the corresponding desktop key (as modified by the active layer of the touch layout) +according to the rules that are in the .kmn file. + +If you establish the desktop keyboard layout and create the On-Screen Keyboard, +you can switch to the Touch Editor and import from the OSK. +This will provide a “tablet” layout, with “default” and “shift” layers. +To switch to a “phone” layout, select the basic template, which rearranges the keys and moves some to a “numeric” layer. +(For more details, see the next topic.) +The result will need to be reviewed and tested, but using this approach may save you some time. + +
+[← Part 4 - Using the Debugger](04-using-debugger)   [Part 6 - Creating a Touch Layout →](06-creating-touch-layout) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/06-creating-touch-layout.md b/developer/docs/help/guides/walkthrough/06-creating-touch-layout.md new file mode 100644 index 0000000000..e7664fb797 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/06-creating-touch-layout.md @@ -0,0 +1,154 @@ +--- +title: Creating a Touch Layout +--- + + +
+Part 6 of the [Keyman Developer Walkthrough](.). + +[← Part 5 - Designing a Touch Keyboard](05-designing-touch-layout)   [Part 7 - Writing Keyboard Documentation Files →](07-writing-keyboard-documentation) +
+ +## Step-by-Step + +- Click on the `Touch Layout` tab on the left. The touch layout is shown, with the `q` key selected and details about the selected key shown on the right. Farther to the right is the Character Map which will be used in a later step. If the Character Map is not displayed, use the `View` menu, `Character Map` menu item to turn on the display. + + +![](images/add-longpress.png) + + +- Click on the `e` key to select it and display its information. +- Click on the `+` button in the `Longpress Keys` section. A new key is added (and the `+` button moved). The new key is given an arbitrary ID (`T_new_103` in this example). + +![](images/new-longpress-key.png) + +- Note that information about this key is placed to the right. + +![](images/longpress-fields.png) + +- We’ve added this longpress key to the `e` key. Now we want to make it (1) display `ɛ` so users will see what the key will produce and (2) change the ID so that activating this longpress key will generate `ɛ`. Find the `ɛ` character in the Character Map and drag it to the `Text` field. This will put `ɛ` in the `Text` field, `U+025B` in the `Text Unicode` field and `U_025B` in the `ID` field. + +![](images/charmap-to-text.png) + +Note: To find the `ɛ` character in the Character Map, you can use the scroll bar on the right to scroll down to `U+025B`. Alternatively, you can type `25B` in the `Filter by` field at the bottom of the character map. + +- Click on the `o` key in the keyboard layout. This will select the `o` key and display its information. +- Click on the `+` button in the `Longpress Keys` section. A new key is added (and the `+` button moved). The new key is given an arbitrary ID (`T_new_104` in this example). In addition, information about this key is placed to the right. +- We’ve added this longpress key to the `o` key. Now we want to make it (1) display `ɔ` and (2) change the ID. We could use the same procedure as in the previous steps, but this time we’ll use a different method. Click in the `Text Unicode` field and type `U+0254` (this will also place `ɔ` in the `Text`, but will not change the `ID` field). +- Click in the `ID` field and replace the generated ID (`T_new_104` in this example) with `U_0254`. (Note that the ID uses an underscore rather than a plus sign.) + +![](images/u-0254.png) + +- Add three longpress keys using one of the above methods: + - on the `n` key, add a longpress key for `ŋ` = U+014B + - on the `g` key, add a longpress key for `ɣ` = U+0263 + - on the `z` key, add a longpress key for `ʒ` = U+0292 +- You've made these five changes on the `default` layer. Now we need to switch to the `shift` layer. Select the drop-down menu under the `Layer` heading and select `shift`. + +![](images/shift-layer.png) + +- With the capital letters displayed on the keyboard, add five longpress keys using one of the above methods: + - on the `E` key, add a longpress key for `Ɛ` = U+0190 + - on the `O` key, add a longpress key for `Ɔ` = U+0186 + - on the `N` key, add a longpress key for `Ŋ` = U+014A + - on the `G` key, add a longpress key for `Ɣ` = U+0194 + - on the `Z` key, add a longpress key for `Ʒ` = U+01B7 +- Select the `Build` tab on the left and then the `Compile Keyboard` button. You should see a `dagbani.kmn built successfully` message. If you don’t, examine the error messages to see where the problem lies. + +### Testing the touch layout + +Keyman Developer provides a way to test your keyboard in a web browser. +- On the Build tab, you can select `Test Keyboard on web` followed by `Open in browser`. +- Select the `Keyboard` drop-down menu, then select the `dagbani` keyboard. You should have a display that looks like: + +![](images/test-keyboard-browser.png) + +- The display defaults to the Windows keyboard. You can type on the computer keyboard or use your mouse to click on the keys. Enter ; e ; o ; g ; z ; n and you should have the following result. + +![](images/test-keyboard-browser-display.png) + +- Select the `Device` drop-down menu and select `iPhone 5S`. The display will change to show a simulated phone screen with your touch layout. You can use your mouse to click on the keys. To access the longpress keys, click and hold, then slide the mouse to select the letter on the longpress key. Try this with the five longpress keys on `e` `o` `g` `z` and `n`. (There’s a dot in the upper right corner of the key to indicate the presence of at least one longpress key.) The period (full stop) also has a longpress menu that allows various punctuation characters to be entered. + +![](images/test-longpress.png) + +- If you click on the `Shift` key, the display changes to the `shift` layer and you can enter characters from that layer. +- When you are finished testing, you can close the browser tab. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 7 - Writing Keyboard Documentation Files](07-writing-keyboard-documentation) +
+ +--- + +## Configuring a Touch Layout + +There are a number of items to the left of the keyboard layout that allow you to configure the touch layout and select what portions to display. If you have done the Step-by-Step tutorial for this page, you’ve seen how to choose a different layer from the drop-down menu under the “Layer” heading. + +### Template and Import from On Screen buttons + +When you are initially creating a touch layout, it may be helpful to start from the On-screen Keyboard you created for the desktop layout and/or from a template. Since using these buttons overwrites the existing touch layout, you’ll only want to use them at the beginning of your touch layout work. + +- `Import from On Screen` will create a `tablet` layout with `default` and `shift` layers from the On Screen keyboard for the `desktop` layout. +- `Template`, then `template-basic` will distribute the keys for a `phone` layout with `default`, `shift` and `numeric` layers. +- `Template`, then `template-latin` will rearrange the keys for a `phone` layout with `default`, `shift`, `numeric` and `symbol` layers. It includes longpress keys for accented Latin characters. An identical `tablet` layout is also created. See the note under `Choosing the Platform` below. +- `Template`, then `template-traditional` will distribute the keys for a `phone` layout with `default`, `shift` and `numeric` layers, but also make a `tablet` layout based on the desktop one. + +### View Options + +By default the list of modifier-based layers is limited to the most commonly used desktop layers +(`default`, `shift`, `rightalt`, `rightalt-shift`, `caps`). +Selecting this option will extend that list to include layer names like `rightctrl-rightalt-shift`. +It doesn’t add these layers to the layout, but merely adds them to the list of predefined names that you could choose to use. +It’s likely you will never want to choose this option. + +You can always choose the `(custom)` option and enter any valid name (limited to A-Z, a-z, 0-9, underscore and hyphen). + +### Choosing the Platform + + Options are “phone”, “tablet”, “desktop” + +- A “phone” layout typically has four rows (counting the row with the space bar) with ten or eleven keys per row. A “tablet” layout typically has five rows with thirteen or fourteen keys per row +- Don’t include both a “phone” layout and a “tablet” layout unless those layouts are different. Keyman will use a “phone” layout on a tablet if no “tablet” layout exists and use a “tablet” layout on a phone if no “phone” layout exists. Thus it is twice the work (or more) to maintain identical “phone” and “tablet” layouts. +- The “desktop” layout option is not currently used. It is intended for Windows touch screens but currently Windows does not make it feasible to support custom touch keyboards. + +### Adjusting Keyboard Layers + +A keyboard layout generally includes multiple layers. (See description of [Keyboard Layer](glossary) in the glossary.) The Touch Layout editor displays one layer at a time. The “default” layer is the layer that is presented when no key (such as Shift) has been used to activate another layer. + +In the Touch Layout editor you switch layers using the drop-down menu described below. In addition, you need to make sure that each of the layer activation keys specifies in the “Next Layer” field which layer is to be activated. For example, on the default layer, the Shift key has “shift” in the “Next Layer” field, and on the shift layer, the Shift key has “default” in the “Next Layer” field. + +Under the “Layer” heading you can: + +![](images/layer-selection.png) + +- choose an existing layer from the drop-down menu to display that layer +- choose the “+” button to add a new layer (either choosing a name from the “Modifier-based layer” list, or choosing “(custom)” from that list and entering a name in the “Name” field) +- choose the “-” button to delete the layer whose name is displayed +- choose the “Edit” button to change the name of the current layer + +## Longpress, Flicks and Multitap Gestures + +If you completed the Step-by-Step tutorial for this topic, you added longpress keys to certain base keys in the touch layout by clicking on the “+” button in the “Longpress” section and supplying the needed information to define the longpress key. + +Similarly, if you wish to add a flick gesture, choose one of the eight “+” buttons in the “Flicks” section — the one that corresponds to the direction that you want to assign for this flick gesture — and click on it. Then supply the needed information to define that flick gesture. + +A multitap gesture is defined in a similar way. Click on the “+” button in the “Multitap” section and add the information to define the multitap key. The base key will respond as normal for a single tap, the first multitap key listed will respond to a double tap, the second multitap key to a triple tap, etc. + +Use care when combining different kinds of gestures as some of them may conflict. + +- Don’t use too many keys in a longpress menu +- Don’t use too many flicks. For example, NE, N, and NW flicks are easily confused +- When using north-flicks and longpress, be aware that the north-flick shortcut for the default longpress will be blocked +- Don’t assign too many multitap keys to the same base key + +## Reference + +See [Touch layout editor documentation](../../context/keyboard-editor#toc-touch-layout-tab) for more details. + +## Testing Touch Keyboards + +See the end of the Step-by-Step section above for a description of how to use Keyman Developer to test your touch layout in a browser window. It’s also possible to transfer the .kmp file to a touch device and install the keyboard there for testing. + +
+[← Part 5 - Designing a Touch Keyboard](05-designing-touch-layout)   [Part 7 - Writing Keyboard Documentation Files →](07-writing-keyboard-documentation) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/07-writing-keyboard-documentation.md b/developer/docs/help/guides/walkthrough/07-writing-keyboard-documentation.md new file mode 100644 index 0000000000..13d70cb317 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/07-writing-keyboard-documentation.md @@ -0,0 +1,113 @@ +--- +title: Writing Keyboard Documentation +--- + + +
+Part 7 of the [Keyman Developer Walkthrough](.). + +[← Part 6 - Creating a Touch Layout](06-creating-touch-layout)   [Part 8 - Preparing a Keyboard Package →](08-preparing-keyboard-package) +
+ +## Step-by-Step + +- Click on the `dagbani.kpj` tab at the top (just under the menu and toolbar), then click on the `Distribution` tab at the bottom. + +![](images/distribution-tab.png) + +- There are a number of files that provide information about the keyboard. Some are for the keyboard author and for maintainers of the Keyman keyboards repository, some are to help users of the keyboard understand how it works. + +![](images/history-md-file.png) + +- In the list of files, click on the `HISTORY.md` one to open that file. The file will open in a text editor and show you the information that you entered when setting up the keyboard project, specifically version 1.0, today’s date, and the author’s name. Since this information is correct, you can close this file by clicking on the red “X” on the righthand side of the `HISTORY.md` tab at the top of the text area. +- Click on `LICENSE.md` to open that file. This has been filled out using the Full copyright information you provided. Close the file by clicking on the red “X”. +- Click on `README.md` to open that file. This has been initialized for you. Close the file by clicking on the red “X”. (This file provides a place for information about the design of the keyboard that would be useful to a keyboard author wanting to update the keyboard or use it as a basis for a new keyboard. Don’t confuse it with the next item which is information for the keyboard user.) +- Click on `source\readme.htm` to open that file. This is the information displayed to the user just before the keyboard is installed. It has the description supplied when setting up the keyboard project. Other helpful information can be added, but the file should be kept as short as possible. Close the file. +- Click on `source\welcome.htm` to open that file. This is the help information that is packaged with the keyboard and available to the user. It should contain enough information so that the user can learn to type with the keyboard. This can be in the form of: + - image files referenced by the welcome.htm file, or + - a chart (in HTML format) showing how two keystrokes produce a character, or + - descriptive text in the HTML file, or + - some combination of the above. +- For this tutorial, we’re going to add one line of instruction. Find the following line: + +``` + +``` + +- Instead of inserting images, we're going to copy the following HTML text and paste it into the file: + +`

Type ";" followed by e o n g z E O N G Z to produce ɛ ɔ ŋ ɣ ʒ Ɛ Ɔ Ŋ Ɣ Ʒ

` + +- Close the welcome.htm file. Click “Yes” to save the changes. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 8 - Preparing a Keyboard Package](08-preparing-keyboard-package) +
+ +## Editing the README.md file + +The `README.md` file contains information about the keyboard useful for other keyboard authors who might revise or adapt the keyboard at some future date. This information is not presented to the end user. + +## Editing the LICENSE.md file + +If you filled out all the information in the New Project dialog, the `LICENSE.md` file should have been set up correctly. +Normally the only thing to change here would be changing the initial date into a date range (from `2026` to `2026-2027`, for example). +Changing the date in this manner is only needed when the keyboard is updated. + +## Editing the readme.htm file + +The `readme.htm` file is displayed as the user begins to install the keyboard. +It should contain a brief description of the keyboard with enough information to reassure the user that the right keyboard has been selected for installation. +Instructions for using the keyboard should be reserved for the `welcome.htm` file. + +## Editing the welcome.htm help file + +The `welcome.htm` file provides the help that is packaged with the keyboard. +This help file is displayed after the keyboard is first installed. +The user can also ask for the help file to be displayed. + +This file should contain enough information that the user can discover all the features of the keyboard. +This could be in the form of +- keyboard images for the different layers, +- a chart of how to type, +- a description of how to type (such as was used in the Step-by-Step tutorial), +- or some combination of these. + +One way to create keyboard images is to use the procedure in the "Exporting an On-Screen Keyboard layout" section of [Creating a Desktop Layout](03-creating-desktop-layout). +These images can be referenced from the welcome.htm file in this fashion: + +```html +

Desktop keyboard layout

+

Default (unshifted)

+

Default (unshifted) state

+

Shift

+

Shift state

+

Right Alt (unshifted)

+

Right Alt (unshifted) state

+``` +All the files to be included in the package must be specified in the Keyman package source (.kps) file. +These files end up in a single directory in the Keyman package (.kmp) file. +Thus it is preferable to put images referenced by welcome.htm in the same folder as the welcome.htm file in order to allow easy local testing. + +There are two approaches: +1. put the welcome.htm file and all the images it references in the `source` folder, or +2. create a `welcome` folder under the `source` folder and put the welcome.htm file and all the images it references in the `welcome` folder. + +Keyman Developer's `New Project` feature follows the first approach when it creates the directory structure for the new project. +If you decide to use the second approach (which might be helpful if you have lots of images to include), +you'll need to change the location of the welcome.htm file in the list of files in the package. +The easiest way to do this is to remove the welcome.htm file from the list, then add it again by navigating to the new location. + +For either of the two approaches, all the image files that are referenced by the welcome.htm file need to be added to the list of files to be included in the package. + +## Editing the PHP help file + +When a keyboard is submitted to the Keyman keyboards repository, a PHP file is included which provides the online help available on the [keyman.com](https://keyman.com) site. (If you do not plan to submit your keyboard to the Keyman repository, you don’t need to include this PHP help file.) + +The Keyman keyboards repository requires that this PHP file have the name of the keyboard project plus the `.php` extension and be located in a folder named `help`, which is located in the `source` folder. + +The PHP help file often contains the same information as is in the welcome.htm file. See [Keyman Keyboard help document (PHP help file)](https://help.keyman.com/developer/keyboards/phphelpfile) for more details. + +
+[← Part 6 - Creating a Touch Layout](06-creating-touch-layout)   [Part 8 - Preparing a Keyboard Package →](08-preparing-keyboard-package) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/08-preparing-keyboard-package.md b/developer/docs/help/guides/walkthrough/08-preparing-keyboard-package.md new file mode 100644 index 0000000000..6a4f769788 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/08-preparing-keyboard-package.md @@ -0,0 +1,66 @@ +--- +title: Preparing a Keyboard Package +--- + + +
+Part 8 of the [Keyman Developer Walkthrough](.). + +[← Part 7 - Writing Keyboard Documentation](07-writing-keyboard-documentation)   [Part 9 - Distributing a Keyboard Package →](09-distributing-keyboard-package) +
+ +## Step-by-Step + +- Select the `dagbani.kpj` project filename at the top (just under the menu and toolbar). +- Select the `Packaging` tab at the bottom, then the `dagbani.kps` file. This will open the Keyboard Package Source file and display some tabs down the left side of the window that will help you manage the content. Most of the information has been set up for you when you first created the keyboard project. + - The `Files` tab lists the files that will be included in the package. + - The `Keyboards` tab lists the language codes supported by this keyboard. +- Select the `Details` tab. +- If the value in the `Welcome file` field is `(none)`, then select that field and select `welcome.htm` from the drop-down list. +- Select `File` in the menu bar, then `Save` to save the changes. (The Ctrl+S shortcut also works.) +- Select the `Build` tab, then the `Compile Package` button. A **dagbani.kps built successfully** message should be displayed. +- Congratulations! You have successfully built and packaged a keyboard for the Dagbani language. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 9 - Distributing a Keyboard Package](09-distributing-keyboard-package) +
+ +--- + +## Package Files + +See the [Keyman Package Editor documentation](../../context/package-editor) if you need more details on the following items. + +### Files + +In addition to the files that are included in the package by default when you create the keyboard project with the New Project feature, you have the option of adding additional files to the package. Files that might be added: + +- keyboard image files referenced by the welcome.htm help file +- fonts +- an image file (see under Details) + +### Keyboards + +Enter a language tag (that is, a BCP 47 tag) for each language supported by the keyboard. + +Optionally, you can specify an example of a word the keyboard produces and the keys used to produce it. + +If you include fonts in the package, you can specify that Keyman use them for displaying the on-screen keyboard or the touch keyboard. + +### Details + +Here is where you can enter information for: + +- Package name: Initially set to the name of the keyboard, so usually won’t need to change +- Welcome file: normally set to `welcome.htm` +- Readme file: normally set to `readme.htm` +- License file: normally set to `LICENSE.md` +- Version: Recommendation is to tick the `Package version follows keyboard version` box and leave the version field blank +- Copyright: normally established in the New Project dialog, but you can make needed changes here. Current practice is to omit the copyright year from this field (since it is in the [LICENSE.md](http://LICENSE.md) file). +- Author, Email address, Web Site: You can include as much or as little information about the author as you wish +- Image file: If you supply a 140 pixel wide x 250 pixel high image in JPEG or PNG format, then your custom image will be shown during installation (in place of the default Keyman image). Your image file must be added to the Files list before it will be available to be selected here. +- Related packages: If your keyboard is part of a group of keyboards, you can specify which other keyboards are part of the group. (For example, you might have three keyboards for the same language, one based on the QWERTY layout, one AZERTY, one QWERTZ, and you could use this field to note the relationship between them.) You can also use this feature to deprecate another keyboard that your keyboard supersedes. + +
+[← Part 7 - Writing Keyboard Documentation](07-writing-keyboard-documentation)   [Part 9 - Distributing a Keyboard Package →](09-distributing-keyboard-package) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/09-distributing-keyboard-package.md b/developer/docs/help/guides/walkthrough/09-distributing-keyboard-package.md new file mode 100644 index 0000000000..1a38688018 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/09-distributing-keyboard-package.md @@ -0,0 +1,38 @@ +--- +title: Distributing a Keyboard Package +--- + + +
+Part 9 of the [Keyman Developer Walkthrough](.). + +[← Part 8 - Preparing a Keyboard Package](08-preparing-keyboard-package)   [Part 10 - Generating a Lexical Model →](10-generating-lexical-model) +
+ +## Step-by-Step + +For the Step-by-Step tutorial, there’s really nothing to do for this page. This tutorial is for learning only, therefore you don't want to submit this keyboard to the Keyman keyboards repository (since it already contains a keyboard by that name). If you like, you could look at the other sections on this page before continuing the Step-by-Step tutorial (or come back to them later). + +
+To continue the Step-by-Step tutorial move to the next page: [Part 10 - Generating a Lexical Model](10-generating-lexical-model) +
+ +--- + +## Submitting a keyboard to the Keyman Keyboards Repository + +Follow the instructions at [Working with the Keyman Cloud Keyboard Repository](https://help.keyman.com/developer/keyboards/) to submit your keyboard to the Keyman keyboards repository. This will enable anyone with Internet access to download and use the keyboard. (Please do not submit the Dagbani keyboard used in the Step-by-Step tutorial. There is already a Dagbani keyboard in the repository.) + +One requirement for keyboards that are submitted to the Keyman keyboards repository is the addition of a PHP help file that provides the online help available on the keyman.com site. See the **Editing the PHP help file** section of the [Writing Keyboard Documentation](07-writing-keyboard-documentation#toc-editing-the-php-help-file) page for more details. + +## Other Distribution Methods + +A keyboard package is contained in a file with the file type `.kmp`. The package contains everything needed for any of the supported platforms to run the keyboard. If you want to test a keyboard package, it is possible to transfer the `.kmp` file to a device with Keyman installed and use Keyman on that device to install the keyboard. + +With Keyman Developer running, it’s possible to select `Packaging`, and the `.kps` file, then the `Build` tab, and then select the `Test package on web`. This will display a number of possible Internet addresses where the keyboard could be downloaded over a local network to a device running Keyman. There are also options that will install the package on the local machine running Keyman Developer. + +The Keyboard App Builder (KAB) lets you put a Keyman keyboard (and optionally a lexical model) into an app for iOS or Android, which can be distributed. More details can be found on the [Keyboard App Builder](https://software.sil.org/keyboardappbuilder/) page. + +
+[← Part 8 - Preparing a Keyboard Package](08-preparing-keyboard-package)   [Part 10 - Generating a Lexical Model →](10-generating-lexical-model) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/10-generating-lexical-model.md b/developer/docs/help/guides/walkthrough/10-generating-lexical-model.md new file mode 100644 index 0000000000..610c3fe913 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/10-generating-lexical-model.md @@ -0,0 +1,376 @@ +--- +title: Generating a Lexical Model +--- + + +
+Part 10 of the [Keyman Developer Walkthrough](.). + +[← Part 9 - Distributing a Keyboard Package](09-distributing-keyboard-package)   [Part 11 - Installing a Keyman Lexical Model →](11-installing-lexical-model) +
+ +## Step-by-Step + +For the purposes of this tutorial, we'll use a very short word list (of only 25 words) +selected from the first chapter of the gospel of Mark from the online version of Dagbani Bible +([https://www.bible.com/bible/2264/MRK.1.DBWDB](https://www.bible.com/bible/2264/MRK.1.DBWDB)). +The sample text is a verse from that chapter, so it is not a very realistic test! +This is just so that you can see how the lexical model is used for predictive text. + +For a real project you would want thousands of words, ideally drawn from a number of sources. +In addition, the list of words should be reviewed. +(For details, see the discussion that follows the Step-by-Step section on this page.) + +- Open Keyman Developer, and select the `Project` menu and the `New Project` menu item. In the `New Project` dialog, select `Wordlist Lexcial Model`, then `OK`. + +![](images/new-lexical-model.png) + +- A `New Wordlist Lexical Model Project` dialog is displayed. +- In the `Author Name` field, put `SIL Global`. This also fills in the Copyright and Full Copyright fields. +- In the `Model Name` field, put `WL` (for `wordlist`). +- The version number defaults to `1.0` and we will keep that value. +- In the `Description` field, put **A test lexical model for Dagbani keyboard tutorial. Not for real use.** +- Select the `Add` button on the right and enter `dag` in the `Language tag` field and select `OK` +- Change the `Author ID` field from `sil_global` to `sil`. +- Verify that the `Model ID` field now shows `sil.dag.wl`, then select `OK`. + - Note: If you are using Keyman Developer 17, it might display the message **This project file is in an old format. You should update it to the Keyman Developer 17.0 project format.** If so, select the `Upgrade project` button. + +- Select the `Models` tab at the bottom of the window, then select the `sil.dag.wl.model.ts` file. +- Tick the `Language uses casing` checkbox (located on the `Details` tab) +- In this tutorial, we're going to open a file, copy its contents, then paste those lines into the `wordlist.tsv` file to replace the default content. Depending on how your browser is configured, when you open the file, it may open in a new tab or it may open in the same tab as this set of instructions. In the first case you can close the tab to return here, but in the second case you'll need to use the Back feature of your browser. (You may want to read ahead to make sure you understand the next few steps since the instructions might be hidden temporarily.) +- Click on the **dag-short-wl.txt** filename just below this paragraph to open the file (or right-click and select Open in a new tab). + + * [dag-short-wl.txt](./dag-short-wl.txt) + +- Use Ctrl+A to select the entire contents and Ctrl+C to copy the selected text. +- Return to these instructions, either with the browser's Back feature, or by closing the newly opened tab, as appropriate. +- In Keyman Developer, select the `wordlist.tsv` tab on the left, then the `Code` tab at the bottom, then use Ctrl+A to select the entire contents and Ctrl+V to paste in the text that you just copied in a previous step. +- Use `File`, `Save` (or, alternatively, the Ctrl+S shortcut) to save the modified wordlist.tsv file. +- Select the `Build` tab on the left, then the `Compile Model` button. Verify that the **sil.dag.wl.model.ts built successfully** message is displayed. +- To test the model, we’ll first select the keyboard that we made in an earlier step. (The following instructions assume that the default location was chosen when creating the keyboard project and the lexical model project. If you chose a different location, you’ll need to navigate there.) Select the `Browse` button and Keyman Developer will open a file navigation window. Navigate to the `Documents` folder, then the `Keyman Developer` folder, then `Projects`, then `dagbani`, then `build`, then open the `dagbani.js` file. This will fill in the `Keyboard for testing` field. + +![](images/test-lexical-model-setup.png) + +- Select the `Test Lexical Model` button, then the `Open in browser` button. You should have a new browser tab that looks like: + +![](images/keyboard-model-device.png) + +- Select the `Keyboard` button and choose the `dagbani` keyboard from the list. +- Select the `Device` button and choose one of the `Phone Devices` from the list. (The illustrations were made with the `iPhone 5S` option.) +- Select the `Model` button and choose the `sil_dag_wl` lexical model from the list. +- Click in the text area (box with pale yellow background). The text we’re using as a test is **Ka bɛ daa dii chɛ bɛ lansi maa ka dol’ o.** You’ll be using the mouse to simulate the phone’s touch screen (unless your computer has a touch screen). Move your cursor to the desired key on the display, then click the mouse to “touch” the key. +- Click the Shift key (the key on the left with an uparrow), then K, then select **Ka** from the banner. + +![](images/test-lexical-model-k.png) + +- Click b, then select **bɛ** from the banner. +- Since **daa** is in the banner already, select it. +- Click d, then select **dii** from the banner. +- Click c, then select **chɛ** from the banner. +- Click b, then select **bɛ** from the banner. +- Click l, a, n, s, i, and the space bar. +- Since **maa** is in the banner already, select it. +- Since **ka** is in the banner already, select it. +- Click d, then select **dol’** from the banner. +- Click o and . to conclude this test. +- Close the browser tab and return to Keyman Developer. +- Select `sil.dag.wl.kpj` from the top of the window (under the menu bar and toolbar), then select the `Packaging` tab at the bottom, then the `sil.dag.wl.model.kps` file. +- Select the `Details` tab on the left. + - If the `Welcome file` field contains `(none)`, select that field and choose `welcome.htm` from the list. Use the Ctrl+S shortcut to save the change. +- Select the `Build` tab on the left. Then select the `Compile Package` button. Verify that you get the **sil.dag.wl.model.kps built successfully** message. +- Congratulations! You have successfully built and packaged a lexical model for the Dagbani language. + +
+To continue the Step-by-Step tutorial move to the next page: [Part 11 - Installing a Keyman Lexical Model](11-installing-lexical-model) +
+ +## Introduction + +A Keyman touch layout can link to a lexical model in order to suggest words to automatically finish what you are typing, based on the characters you have already entered. The currently available lexical models only predict words based on how frequently they are used in the entire language, and will not suggest next words according to context or grammatical rules. However, for languages with long words or complex character combinations, lexical models can be a valuable tool to aid users of your keyboard. + +## Before You Begin + +In order to create a lexical model for a language, you should have one or more sources of words in the language. Examples could be: + +- Text files written in the language of your lexical model +- A lexicon or dictionary, from which you can export a list of words + +You should choose sources with open licenses (such as Creative Commons, MIT, etc). You may need to ask the source for permission to relicense the list of words under the MIT license if you submit the lexical model to the Keyman lexical models repository (which always uses the MIT license). + +## Creating a Lexical Model + +Keyman Developer allows you to create a lexical model project, which is separate from your keyboard project. The link between a keyboard and a lexical model depends on having a BCP 47 code in common. Although it may seem confusing to make a separate project for a lexical model that is intended to go with your existing keyboard, this separation allows a lexical model to be used by any keyboard that supports that language. Similarly a keyboard user might have multiple lexical models to choose from. + +In Keyman Developer, from the `Project` menu, select `New Project`. In the `New Project` dialog, select `Wordlist lexical model` from the list. Another dialog will appear to collect the basic information for your model. + +### **Author Name, Author ID and Copyright** + +Enter your name in the `Author Name` field. The value in this field is also used in the `Copyright`, `Full Copyright` and `Author ID` fields. If the copyright is held by an organization, adjust the name in the copyright fields. The name that appears in the copyright fields needs to be the full name of an individual or organization. + +The `Author ID` value is based on your name (if you are working independently) or the name of your organization. You should use the shortest feasible version of the name (initials, for example), since the `Author ID` is the first of the three parts of a lexical model project. It will also become the parent folder in Keyman’s repository for all lexical models submitted by you or your organization. + +### Model Name + +This is the third of the three parts of the complete lexical model project name. It serves to distinguish between multiple lexical models by the same author for the same BCP 47 tag. + +You could use: + +- the name of the language this lexical model will serve +- some indication of the source of the words +- the type of lexical model, such as “wordlist” or “wl” (since Keyman currently only supports wordlist-based models) + +As with the keyboard project ID, you are limited to lower case ASCII alphanumeric characters and the underscore character. + +### Version + +For a brand new model, there is no need to edit this. However, when making changes or additions to a lexical model, increment the first digit (for example, from `1.0` to `2.0`) for major changes, and the second digit (for example, from `1.0` to `1.1`) for minor changes. (As with the version number for keyboards, an optional third digit is available for revisions. Do not use more than three numbers. Don’t add zeroes to the beginning of numbers.) + +### Languages + +As with a keyboard, you must add a BCP 47 tag to your lexical model to properly identify the language it is intended for. This is the link that allows Keyman to match keyboards and lexical models. It will be used as the second of three parts of the complete lexical model project name. + +Select `Add` and fill in the fields accordingly. You’ll want to use the same BCP 47 tag which you used in the [Creating a Keyboard Project](01-creating-keyboard-project) step. + +![](images/add-language.png) + +It is best to use the simplest possible BCP 47 tag to identify your language. Only add Script and Region tags if you are specifically working with a script or region that differs from the most commonly used form of your language. + +### Description + +For the `Description` field, you can simply state that this a lexical model based on a list of words for the specific language. You might also include information about where those words were gathered. (Don’t, however, include details about how many words are included. Otherwise you’ll need to revise the description everywhere it’s used for each new version of the lexical model that changes the word count!) + +Note how the `Model ID` field is automatically filled in. +The naming scheme for lexical models is `author_name`.`language-tag`.`model_name`. +The `language-tag` value is derived from the `Primary Language` that you choose, so be sure to select the correct language. +If your Author or Model names are excessively long, edit the `Author ID` and `Unique Name` fields respectively to give your project an abbreviated name. (For example, in the Step-by-Step section, the Author field was changed from "sil_global" to "sil".) + +Once you have filled out all of the fields, you are ready to create your lexical model. + +## Details + +Keyman will place you in your `.kpj` file immediately, as with a keyboard project. Navigate to your `model.ts` file. On the `Details` tab, you’ll find some options. + +Currently `Wordlist (trie-1.0)` is the only choice for the `Format` field. + +You’ll normally want to keep the `default` choice for the `Word breaker` field and the `(Space U+0020)` option for the `Insert after word` field, unless you are dealing with an orthography that doesn’t use space to separate words. For scripts such as Khmer, Thai, and Lao, which have special ways to delimit words, see the Keyman documentation on [coding a custom word breaker](../../guides/lexical-models/advanced/word-breaker). + +You can specify the opening and closing quotation marks, and whether the language is using a right-to-left script (such as Arabic, Hebrew, Syriac, etc.) + +If your language uses a script with uppercase and lowercase (such as Latin, Cyrillic, Greek, etc.) you probably will want to enable the `Language uses casing` checkbox, so that Keyman will take casing into account when matching and suggesting words. For example, if you start typing `Rab`, Keyman will propose `Rabbit` rather than `rabbit`. + +The Keyman site has more details on [advanced topics](../../guides/lexical-models/advanced/word-breaker). + +## Editing Wordlists + +On the `Details` tab, there is a field labeled `Wordlists`, where one or more wordlist files are specified. Every wordlist that you add to your lexical model will be listed in the “Wordlists” list on the “Details” tab and have its own tab below the “Details” tab. + +Keyman provides a default `wordlist.tsv` file for you as an example. You can replace its contents with your own data or remove it. Use the buttons on the right to add or remove wordlists. + +For a newly created project, the only wordlist present is `wordlist.tsv`. +If you open that file, you'll see some sample data included as an illustration. + +For advanced information on Keyman wordlist file formats and exporting your own wordlist files, read the [TSV file documentation](../../reference/file-types/tsv). + +### Ignored lines + +Any line beginning with `#` is ignored. You can write any notes or commentary on such lines. + +### Word Form + +The `Word Form` is the first column of your wordlist, and will contain every single word that you want your lexical model to suggest to users while typing. Naturally, this includes grammatical variations and other alternate forms of words used in your language. + +### Count + +The `Count` is the second column of your wordlist, and is a number indicating the relative frequency with which a word appears in your language. This is most commonly done by an automated count of words that occur in actual texts in your language, but it is possible to manually adjust the frequency count of one or more words. + +If the `Count` field is empty for a given word, it will be counted as one. If you omit the `Count` field for all the words in a file, they will all be considered equally likely. Your lexical model will be more useful if it can suggest words according to how common they are. + +Since a lexical model project can have multiple wordlist files, you could have one file with words and frequency counts derived from actual documents in the language, then add a second file extracted from a lexicon with no frequency count. +When compiling the model, Keyman Developer will add the counts. +In this way the lexicon will provide some less common words with a frequency count of one (and increase by one the frequency count of words in the first wordlist). +Thus the list from the lexicon can supplement the list formed by analyzing actual documents. + +### Comment + +The `Comment` is the third column of your wordlist. This is an entirely optional column, but if you would like to leave notes for certain words, you can insert your notes into the third column of your `.tsv` file and Keyman will ignore them while processing your wordlist. + +### Simple Tool for Wordlist Creation + +PrimerPrep is a tool that will extract words from text files and create a simple .tsv file in the correct format for use in your lexical model. +The [Generating Wordlists with PrimerPrep](#toc-generating-wordlists-with-primerprep) section at the end of this page gives a brief tutorial on how to use PrimerPrep to create a wordlist suitable for your lexical model. + +### Importing Wordlists into Keyman Developer + +In Keyman Developer, with your lexical model project open and the .model.ts file selected, select the `Details` tab to see the list of wordlist files included in this lexical model. If you have another file (perhaps one created with PrimerPrep) which you want to addd, select the `Add` button on the far right and navigate to the file to be included. You’ll see a dialog something like the following: + +![](images/copy-wordlist.png) + +Click `Yes` so that Keyman can make a copy of this file to include with the other source files your lexical model project. + +You’ll also want to `Remove` the default `wordlist.tsv` file (unless you have replaced the example content with your own data). + +Note that if you remove a wordlist (the default `wordlist.tsv`, for example) from the `Wordlists` list on the `Details` tab, the file itself will not be removed from your project folder. +You will have to use a file manager to delete any unnecessary wordlist files yourself. +If you decide not to use the default `wordlist.tsv` file, you should remove it from the list on the `Details` tab, then delete it from your project files. + +Once you have specified one or more wordlist files, save your project and compile it. +You should now have a lexical model that is compatible with any keyboard that uses the same BCP 47 tag as the lexical model. + +## Testing Lexical Models + +To test your lexical model, go to the `Build` tab of your `model.ts` file and click `Test Lexical Model`. Keyman will start up a development server to let you test keyboards and models on the web. + +If you are working with your own keyboard and lexical model and have previously compiled your keyboard and run it on the Keyman development server, it will already be among the options for testing. +However, you can also add your keyboard for direct testing in the `Keyboard for testing` field. Simply click the `Browse...` button and search for your keyboard’s `.js` file. It should be located inside your keyboard’s `build` folder. + +Once Keyman confirms that your testing server is active, you can scan the generated QR code with a mobile device to begin testing. + +Another testing possibility is to select the `Open in Browser` button and a new browser window (or tab) will open with three dropdown lists at the top of the page: `Keyboard`, `Model`, and `Device`. +- Set the `Device` to one of the `Phone Devices` or `Tablet Devices` options. +- Set `Keyboard` to the keyboard you selected. +- Then set `Model` to the lexical model you are testing. You can then test the lexical model on the simulated keyboard. + +## Packaging + +Just like a keyboard, the lexical model must be packaged before it is ready for distribution and use with a Keyman keyboard. +Use the `Packaging` tab at the bottom of the screen and select your .kps file. +You can then select the `Build` tab on the left and then the `Compile Package` button to create the package (.kmp) file. + +## Publishing a Lexical Model + +You can submit your lexical model to the Keyman lexical models repository in a manner similar to submitting a keyboard to the keyboards repository. +This makes the lexical model available to anyone with Internet access. +See [Guide for Lexical Model Submissions](/developer/lexical-models/submission/). + +The [Distribute lexical modes to Keyman Applications](../lexical-models/distribute/packages) page details other distribution possibilities. + +In addition, it is possible to use [Keyboard App Builder](https://software.sil.org/keyboardappbuilder/), which will allow you to build an app that includes Keyman, a specific keyboard and a specific lexical model. +You can then distribute this app to users directly or through the platform's source of apps. + +## Generating Wordlists with PrimerPrep + +Creating a wordlist manually is a difficult task. +Instead, wordlists are usually generated using a software tool that can process text files written in the given language, +identify unique words and tally up how frequently they appear in the text. + +One tool that can do this is [PrimerPrep](https://software.sil.org/primerprep/), which is available for free on Windows and Linux. This tutorial will cover how to use PrimerPrep to generate a wordlist from preexisting texts. + +Before generating a wordlist with this method, you must first have one or more texts to take words from. This allows you to include relevant and commonly used words and their various grammatical forms in your lexical model, rather than attempting to select appropriate words yourself. + +When selecting texts to use in generating your lexical model, try to find long texts that include a variety of formats and uses of the language. This increases the likelihood that your lexical model will cover common wordforms and accurately predict the most frequently used words. + +Be sure to back up the original text and save your edited version under a new name. You will need to cut various unwanted words from the document before generating a wordlist from it, which is obviously undesirable if you need the full document later. + +For the purposes of this tutorial, we’ve provided a sample text that you can download and use to follow along with instructions. If you already have a project in mind and appropriate sample texts, feel free to use those instead. + +The sample text is a collection of folktales for the Fulfulde language. Right-click on the **Anduna_anndaaka.txt** link below and select `Save link as` and navigate to a folder where you can save the file and work on it. After you have deleted some unneeded words from the file you'll use PrimerPrep to create a wordlist file that you will then include in the `source` folder of your lexical model project. + +* [Aduna_anndaaka.txt](./Aduna_anndaaka.txt) + +### File Preparation + +Before extracting words from a document to create a wordlist, you can first remove any words that are unlikely to be needed by users. (Alternatively, you can create the wordlist first and remove unwanted words later, but that may end up being more work.) + +Generally, you'll want to exclude such words as: + +- Proper nouns (names, places, etc.) +- Acronyms and abbreviations (e.g. D.I.Y., LHR) +- Numerals and extra symbols +- Anything that is not used as a regular word in the language + +PrimerPrep will remove any punctuation and numerals for you when it processes your document, but you will need to remove proper nouns and acronyms before using PrimerPrep. The easiest way to do this is with Regular Expressions (Regex), which allow you to quickly find specific strings of characters and remove them from your document. + +If you do not have a word processing app that supports Regex searches, you can download and use the free program [Notepad++](https://notepad-plus-plus.org/downloads/). Otherwise, feel free to use your Regex-compatible word processor of choice. + +When you open the Aduna_anndaaka.txt file you’ll notice that the title page is written in French. Delete everything that comes before the following line: + +``` +Aysata Aamadu Siise +``` + +The lines before it are either in French or contain mostly acronyms or proper nouns, which we do not want to include. + +In general, you will want to ensure that the text you are processing contains only text in the language for which you want to create a lexical model, so that your model won't suggest words in a different language. +This is especially important if you are using a text that contains translations or other footnotes meant for non-native speakers. + +Open up the file you want to take your wordlist from in Notepad++. In our case, this is `Aduna_anndaka.txt`. +In Notepad++, press Ctrl+H (or from the `Search` menu, select `Replace`) to open the Find and Replace dialog. +Enable the `Regular Expression` setting at the very bottom. + +![](images/notepadpp-regex.png) + +You will need to perform several Regular Expression (Regex) search and replace operations to remove unneeded elements from the document. +For each Regex string, simply paste it into the `Find what:` field, and leave the `Replace with:` field blank. +(A blank “replacement” effectively deletes what the search finds.) + +The regular expressions provided here are tailored for the Fulfulde language, which includes the characters `ɓɗɲŋƴ` and `ƁƊƝŊƳ`. +You may have to dive deeper into Regex rules to filter words in languages that use different character sets. +[Regex101](https://regex101.com/) is a great resource for building and testing regular expressions. +Just make sure that the Regex “flavor” you use on the site matches that of your word processor. + +### Removing Proper Nouns + +``` +\b[A-ZƁƊƝŊƳ][a-zɓɗɲŋƴ]*\b +``` + +This Regex searches for any words that begin with an uppercase letter followed by zero or more lowercase letters. +(The `\b` represents a word boundary. `[A-ZƁƊƝŊƳ]` represents one of 31 uppercase letters. `[a-zɓɗɲŋƴ]` represents one of 31 lowercase letters, however `*` indicates that `[a-zɓɗɲŋƴ]` should be repeated zero or more times.) +Although it will also remove any words that begin a sentence (or words that are in titles), it will remove most unwanted names. +The idea is that if a word is common enough, it will appear multiple times in different places, so it is acceptable to remove the few times the word happens to begin a sentence. + +- Make sure to activate the `Match case` option when using Regex to look for capitalized letters. Otherwise, it will match words of **any** case (and may replace your entire document)! + +![](images/notepadpp-case.png) + +- Copy the regular expression above and paste it into the `Find what` field. +- Select the `Find Next` button a few times to see what Notepad++ is matching. It should be highlighting capitalized words only. (Note that Notepad++ highlights the matched word in one color and also, in a slightly different color, any other occurrences of the same word, **regardless of case**. This can be confusing.) +- Once you’re satisfied with the results, return to the top of the file and select `Replace All`. + +### Removing Acronyms + +``` +\b([A-ZƁƊƝŊƳ][.-]?)+\b +``` + +This Regex will remove all words that are either in ALL CAPS, or in caps with separating punctuation (i.e. D.I.Y.). +Note that if the acronym does have separating punctuation, there may be one last `.` left on the end. +This is not a problem because PrimerPrep will clean up all of the punctuation for us later. + +- Return to the top of the file +- Copy the regular expression above and paste it into the `Find what` field. +- Select `Find Next`. In this case, you will likely get a `Can't find...` message, indicating that no matching acronyms were found. +(If it is matching random words, ensure that `Match case` is checked.) +For this text, this particular test wasn't needed. Deleting the front matter from the text removed several acronyms already. + +Your text should be ready for PrimerPrep now. It may look messy to a human, but PrimerPrep will ignore all of the extra spaces and punctuation and simply extract the words from the document. It will look something like this: + +![](images/primerprep-input.png) + +- Save your file with a new name (`Aduna_anndaaka_lowercase.txt` for example) and place it somewhere that will be easy to find. + +### Generating the Wordlist + +- If you haven’t already, download [PrimerPrep](https://software.sil.org/primerprep/downloads/) and run it. This is the basic appearance: + +![](images/primerprep-start.png) + +It may look complicated, but the wordlist generation only uses one of the functions of PrimerPrep. + +- Select the `Add Text(s)` button +- Navigate to the text you just prepared +- Double-click on the file (or select the file and then select `Open`). It should populate the window with words and frequency counts: + +![](images/primerprep-with-words.png) + +- From the `File` menu, select `Save Word List` and save your wordlist file in an appropriate location. Be sure to rename it something that distinguishes it from any other wordlists you may generate. PrimerPrep suggests a `.txt` extension, but Keyman generally uses `.tsv` + +That’s all you need to do. You can now exit PrimerPrep and return to Keyman Developer. PrimerPrep will warn you about unsaved data, but you can safely ignore this because you have saved the wordlist file and don't need other functions of PrimerPrep. + +Note: The text provided for this tutorial is already in a `.txt` file format. For your own project, you may be working with files in other formats and you will need to convert them to a `.txt` file in UTF-8 Unicode encoding in order to import them into PrimerPrep. For example, if your files are in Microsoft Word format, the dialog for saving a `.txt` file would look something like this: + +![](images/windows-save-txt.png) + +
+[← Part 9 - Distributing a Keyboard Package](09-distributing-keyboard-package)   [Part 11 - Installing a Keyman Lexical Model →](11-installing-lexical-model) +
\ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/11-installing-lexical-model.md b/developer/docs/help/guides/walkthrough/11-installing-lexical-model.md new file mode 100644 index 0000000000..367863b8e9 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/11-installing-lexical-model.md @@ -0,0 +1,37 @@ +--- +title: Installing a Keyman Lexical Model +--- + + +
+Part 11 of the [Keyman Developer Walkthrough](.). + +[← Part 10 - Generating a Lexical Model](10-generating-lexical-model) +
+ +## Step-by-Step + +For the Step-by-Step tutorial, there’s really nothing to do for this page. +This tutorial is for learning only, therefore you don't want to submit this lexical model to the Keyman lexical-models repository. +You could look at other sections on this page if you like. + +This concludes the walkthrough. Hopefully it has given you an overview of the entire process. + +--- + +## Submitting a lexical model to the Keyman Lexical Models Repository + +Follow the instructions at [Working with the Keyman Cloud Lexical Models Repository](https://help.keyman.com/developer/lexical-models/) to submit your lexical model to the Keyman lexical models repository. This will enable anyone with Internet access to download and use the lexical model. (Please do not submit the Dagbani lexical model used in the Step-by-Step tutorial. It’s really not suitable for submission to the repository.) + +Once the lexical model has been published, any Android or iOS device with Keyman installed and access to the Internet should be able to access and load the lexical model for use with a keyboard with the same language tag (BCP 47 code) as the lexical model. + +## Other Distribution Methods + +If an Android or iOS device has access to the Keyman package file (.kmp) that contains the lexical model, the Keyman program on the device can load the model. This access could be over the Internet, over a local network or by moving the file to the device’s file storage. + +As mentioned earlier, the Keyboard App Builder (KAB) lets you put a Keyman keyboard along with a lexical model into an app for iOS or Android, which can be distributed. +More details can be found on the [Keyboard App Builder](https://software.sil.org/keyboardappbuilder/) page. + +
+[← Part 10 - Generating a Lexical Model](10-generating-lexical-model) +
diff --git a/developer/docs/help/guides/walkthrough/Aduna_anndaaka.txt b/developer/docs/help/guides/walkthrough/Aduna_anndaaka.txt new file mode 100644 index 0000000000..545a0a1ad2 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/Aduna_anndaaka.txt @@ -0,0 +1,439 @@ + +Adunaaru anndataako +(Le monde est inconnu) + +Aysata Aamadu Siise +e Haawa Amiiri Duwansa + +Un livre de contes, proverbes, etc. + +Ecrit par Aysata Aamadou Cissé +Raconter par Hawa Amiri de Douentza + + + + + + + + +© Tous droits réservés, 2001 + +Dépôt : + +MELM, B.P. 33 Sévaré + +Jannde Fulfuldé, B.P. 34 Sévaré + +Puɗɗooɗe: + Miɗo winnda dewtere ndee fewtude e tokara am Ay Daado, abbam e mammam. + Haawa Amiiri Duwansa pillaniiɗo kam ɗii fillaaji e puri. + Teddungal manngal e MELM e PDI-MELM laatiiɓe sabaabu faa dewtere ndee waɗee. + Mi barkinii sanne Aminata Sidibe (Anne Lise), Abdullaayi Bari (Morten) e Umaru Siise (Ingvald Frøyen), hooreejo PDI-MELM Alayiɗi Bari, Bookar Ba, Mawluudu Dikko, balluɗo kam e gollidiiɓe am fuu e ley porojee oo. + + +Aysata Aamadu Siise +Hammadiyel kinkeƴuru + Ɗum waɗiino debbo gooto e gorum, debbo oo haamili tan gorko oo ɲawi, o wii o hulii! So o maayii, so debbo oo ana rima fuu hippa la'al kirtorgal makko ngal de o rima, so suka oo gorko duu o inndira ɗum Hammadiyel kinkeƴuru. O waɗi non. Ko suka oo mawni ɗum, o wii inniiko: +• Ko tawu-mi abba ana golla? +Inna oo wii: +• Abba maa o donsanke. +Cukalel ngel ɓami malfa abba mum, fiɗi lelli, jaawle e kulle ladde hokki inna mum faa ɓe ɲaama. + Amiiri wuro ngoo duu ana wiyee Hammadi Arɗo, omo jogii ndawwal, so ngal warii e boɓi fuu neɗɗo suusaa riiwde ngal faa ngal haara, so gawri maa timmi fuu timmii, walaa ko mbaaw-ɗaa, sabi riiwataake Amiiri jey ngal. + Ɲannde wootere ndawwal ngal wari watti hundoko mum e ley wowru inna Hammadiyel kinkeƴuru, inna oo huli, seli unde faa o wari, o wii: +• Inne, ko saabi a riiwataa foondu nduu ana ɲaama gawri maa? +Inna oo wii: +• Miɗa hula, ɗum ndawwal Amiiri. +Hammadiyel kinkeƴuru fii ndawwal, nanngi ngal, hirsi, hokki inna mum defa. Kaɲum duu ana defa tan ana henta nebbam ana watta e looɗe. + Hiiri ndawwal ngal wartaali, inna Hammadi Arɗo yalti ana tewta faa futoro, o yiitaayi. Nden o noddi garibaaɓe, o wii: +• Njaa garbinowa e ley cuuɗi faa o faama homo hirsi ndawwal ɓiyiiko ngal. +Non gariibu gooto wari ɗo Hammadiyel kinkeƴuru, inniiko wii: +• Alla new gariibu +Tan o wii: +• Ko saabi? +• Alla kaa newii, sabi mi warii ndawwal Amiiri annii tew faa heewi. +O tacci tew, o hokki gariibu oo. Kam duu holloy inna Amiiri. + O warti fajiri faa o taƴora ɗum, o yehi suudu Hammadiyel kinkeƴuru o tawaay oon ton, o wii inna mum: +• Yalla maataay nebbam ndawwal faa o watta e nowru taaniiko? +Inna oo wii: +• Maataay! +O wari faa o yalta fuu o hawri e Hammadiyel, wii: +• Ee! Inne kori jam waddi maa faa gaa. +O wii: +• Ɓinngel mon nowru mum naawata, de sabi a donsanke ngar-mi ndaardude ma nebbam ndawwal. Inna maa wii: Walaa! +Hammadiyel, wii: +• Inne war heey! Njehen faa mi hokke. +Inna Amiiri yehi, Hammadiyel nanngi mo wari mo. O ɲowi daage o watti ɗum ton. Gujjo ana hetti e maɓɓe, o acci faa jemma hejjere o noddi gen gujjo oo, o wii: +• War nanngu. +o nanngi o resowi tew inna Amiiri ley faddaare faa e ley leeso. + Nde gorko oo wari nden, o wii: +• Hannden kaa mi heɓaali fay huunde. +Debbo oo wii: +• Anndan Alla faddaare huurnde keɓu-ɗaa de a wii a heɓaali. +Gorko oo wemmbaa, o wii debbo oo wadda ɗum, o waddi, ɓe itti, ɓe tawi inna Amiiri. Ɓe mbii ɓe mbonii! Sabi ɓe mbarete. Debbo oo wii: +• En ɓaman ko njogi-ɗen fuu e aduna kokken Hammadiyel faa bilta en e bonnde ndee. +Ɓe njehi ɓe kaalani mo ɓe kokki mo. O nanngi fuu, jawdi ndii e maayɗo oo. + Faa hiiri, futoro wari, o yehi caggal ngenndi o tawi ton ittooɓe njumndi, o waɗi daande makko hono daande debbo, o wii: +• Jam hiiri kokkeree kam njumndi +Ɓe mbii: +• Aan homo? +O wii: +Miin inna Hammadi Arɗo. +• Min kokkataa! Ko min kokki Amiiri ɗum fuu heƴataa faa ngaraa gaa mbeeraa min. +O wii: +• Miin so on kokkaay kam tan mi maayan. +Ɓe mbii: +• Maayu! +Tan Hammadiyel faɗɗi inna Amiiri, hono ko o wii o maaya ɗum: +• O maayi! +Ɓe ngari ɓe tawi omo fukkii. Ɓe kuli, ɓe mbii: +• So miɗen anndi a maayan, min kokkerete njumndi ndii fuu. +Tan ɓe mbii: +• En mbarete en fuu. + Gooto e maɓɓe wii: +• Njehen to Hammadiyel kam tan waawi biltude en e ndee bonnde. +Ɓe njehi ɓe kokki Hammadiyel ko ɓe njogii fuu e aduna faa nannga tew inna Amiiri oo e junngo maɓɓe. Hammadiyel wii wooɗi, nanngi maayɗo oo resi. + O yehi to Amiiri, o wii: +• Tokara, mi nanii ndawwal maa lallii, inna maa lallii. Tokara, ɗaana ɲalooma de ndoomaa suudu maa jemma, ko maatu-ɗaa fuu piɗaa. +O wii: +• Wooɗi! +Tan o waɗi non. Hammadiyel ɓami tew inna Amiiri, wari galle Amiiri ley jemma waɗi koso-koso Amiiri ɗojjini malfa mum, fiɗi ɓanni inna oo heɓi ɗum ɓecce, o fukkini ɗum, o dilli. + Fajiri wari, Amiiri wii: +• Hankin mi fiɗii huunde kaa mi anndaa ko ɗum. +Ɓe tawi inniiko, o ɓami ɗum, o irowi ɗum. Amiiri wii ɗum golle Hammadiyel, noddanee kam o wara. Hammadiyel kam wari inniiko e ndawwal makko. Hammadiyel wii: +• Ngoonga, sabi ndawwal ngal ɲaami gawri innam, mi warii ngal, inna maa wari martude kumpa, mi warii ɗum. +Amiiri lamndii hono o haani waɗeede. Ɓee mbii o hirsee. Ɓee mbii o hettee kusel kusel. Ɓee mbii o duppee, mo waree. Hammadiyel lamdii yalla ana waawi haalude, ɓe mbii omo waawi. O wii: +• Maayo men ngoo, won naɗɗo e maggo so yalti abada? +Ɓe mbii: +• Walaa. +O wii: +• Amiiri, kokkaa maccuɓe maa ɓee ngaari ɓe kaɓɓa kam faa mi yoora, ɓe pukkina kam daande maggo ɓe ɲaama tew nagge oo faa ɓe kaara, ɓe kunca kam ɓe paɗɗa kam e ley maggo. +Maccuɓe fuu mbii: +• Ngoonga, ngoonga! +Ɓe ngarri non. Hammadiyel ana fukkii daande maayo ngoo ana doomi. + Faa gorko goɗɗo feri wuro muɓɓen, sabi mawniiko laaminoo ko oon maayi ɗum omo haanunoo laamaade, kaa wuro ngoo wii Hammadi amiiri maayɗo oo ɓurani ɗum, tan o ɓerni o feri. O tawi Hammadiyel ana haɓɓaa ana fukkii. O maati koyɗe puccu gorko oo fuu, o fuɗɗi wullude, o wii: +• Mi laamataako dee kinaa mi laamoo, mi waawaa ittude jakka, mi waawaa ittude muddi, de so mi laamaaki fuu, on paɗɗan kam e ley maayo. +Gorko oo nani, darii, wii kam kaa ana yiɗi laamaade. Hammadiyel wii: +• Humtan faa mi haɓɓe tan. +Ɓe ngaɗi non. + Hammadiyel hooƴi puccu makko waɗɗii, wii mo: +• So ɓe ngari fuu mbiyaa: Miɗe laamoo, tan ɓe kumtete laamowo-ɗaa wuro ngoo. +O wii: +• Wooɗi. +Nde maccuɓe ɓee tilii ɲaamde ngari kunci mo, o wii: +• Miɗo laamoo +Ɓe nootaaki, ɓe paɗɗi mo ley maayo, ɓe mbii: +• O haanɗii. + Hammadiyel hooti suudu muɓɓen ina ɲaama, ana ɲammina puccu mum, faa ɓe payi sanne. Njumndi ndi o heɓunoo ndii, o wii inniiko: +• Moƴƴinanam jiminta maaro e jiminta gawri. +Ɲannde wootere o pari puccu makko faa gasi, o watti jiminta oo e ley danngaaji puccu makko. O yehi suudu Amiiri. Puccu kuu fayi faa ana hulɓinii. O wii cile tati: +• Assalaamu aleykum tokara +Amiiri nootii, o wii ɗum: +• Puccu kuu yo ndoontoori laakara +O hokki ɗum jiminta maaro, o wii ɗum: +• Oo dumo maaro +O jiminta gawri oo, o wii: +• Dumo mbayeeri, kaa mi heɓaali dumo gawri, sabi rewɓe cottaali gawri. +Saaraaɓe maa ɓee ana njiɗi yiide ma. +O wii: +• Hono ngaɗan-mi? +O wii: +• Kokkaa maccuɓe maa ɓee ngaari, ɲaama, paɗɗe e ley maayo a yiidan e laakaraa a yiyan inna maa e abba maa. +O wii: +• Wooɗi. +O waɗi non, ɓe paɗɗi mo e ley maayo. Tan Hammadiyel warti suudu, o wii: +• Abada on njiyaay maayɗo so warti, nii mo warti! +O wii: +• Amiiri maayii. Mo jokkaay kam fuu, mi waran ɗum. +O laatii Amiiri. O ɓamti rewɓe Amiiri, suudu Amiiri nduu o watti inniiko, o laamii wuro ngoo! +Debbo e ɓiyum debbo + Waɗiino e jamaanuuji, debbo gooto e gorum ana ngondi, kaa ko debbo oo rimi fuu, gorko oo ɲaaman. Faa ɲannde wootere o rimi ɓiɗɗo debbo, o wii gorko oo: +• Sabi Alla accanam ngel kaa, faa mi yiya engel ŋaara. +• Haya so ngel waawi fuu, mi ɲaaman ngel. +Worri non, faa ngel waawi ŋaarude, gorko oo wii: +• Sarti oo yottike, mi ɲaaman ngel. +Inniigel oo wii mo kasen: +• Accanam mi yiya engel surbinɗina, sabi abada mi yiyaayi ɓiyam surba. +Ɗum welaali gorko oo, kaa o hulii gite debbo oo, o wii o jaɓii. + Nii debbo oo haaldi e baylo sehana ɗum leggel ɗo suka oo waawi naatude. Inna oo soodi kaŋŋe, cardi e kaddule faa keewi, o watti e ley leggel ngel. + Ko ngel surbinɗini koo, abba oo wii: +• So weetii fuu mi teenoya leɗɗe, de mi warta mi ɲaama cukalel am ngel. +Debbo oo wii: +• Mi jaɓii. +Fajiri law gorko oo dawi teenoyde leɗɗe faa wara ɲaama ɓiyum oo. + Debbo oo wii ɓiyum oo naata ley leggel ngel de doga, sabi so abba mum tawii ɗum ɗoo fuu, ɲaaman ɗum. +• Ɗo njaa-ɗaa fuu mbiyaa: «Giɗo Alla ɗo leggel ɓaaroo.» +Suka oo wii wooɗi, o waynondiri e inniiko, o dilli faa abada. + Debbo oo dogi, naati ley wuro, soodi mbeewa paynga faa sanne, o hirsi nga, o defi faa ɓenndi, mukisii. + Nde gorko oo wartunoo teenoyde ndee tawi tampii, yolbii faa sanne. Ndeen debbo oo wii mo: Mi heppii ma, mi hirsanii ma suka oo, mi defii faa ɓenndii. + Ɗum weli gorko oo sabi tawii yolbii sanne, o ɲaami, kaa o wii: +• Tew oo walaa dakam sabi suka oo ƴaanɗii. +Kaa o annditaali ɗum tew mbeewa. + Suka oo caggal wittii, yehi e wuro wooto, wii: +• Giɗo Alla ɗo leggel ɓaaroo. +Neɗɗo gooto wii mo: +• Ya suudu Amiiri. +Mo yehi, mo lamndii Amiiri, o hollaa, o tawi ton inna mum, o wii noon, inna oo wii mo: +• War, doomu faa Amiiri wara, so mo jaɓii tan gasii. + Ko Amiiri wari koo, inna mum haalani ɗum haala suka oo. O wii: +• So o jaɓii, so tawii puccu am kuu ana silla fuu, mo yalta ku silla dow makko, so ɲallooɓe am ɓee ana tutta, naa ana kaartoo tutta dow makko. So mo jaɓii ɗum nii, annii, o heddoo ɗoo, so mo jaɓaali ɗum duu, mo yalta suudu am nduu. +Leggel jaabii, wii: +• Mi jaɓii abba. + Mo worri non ley galle Amiiri oo, faa ɲannde wootere, wiyaa: Kuurtungu ana waɗa e gure ɓadiiɗe ɗee, Amiiri’en cihe ɓadiiɗe ɗee fuu ngaran, kawra ton. Noon njaatigi leggel oo duu yehi. + Leggel wii debbo mawɗo oo ana yiɗi kaɲum duu yaade e kuurtungu oo. Debbo mawɗo oo jaabii, wii: +• Miɗo hula, sabi so Amiiri yii ma ton fuu riiwete e galle mum oo. +Leggel wii: +• O yiyataa kam, sabi kanko, to fijooji e kelle ton mo tawetee, miin to unooɓe e defooɓe ton ngon-mi. +Inna Amiiri wii mo: +• Wooɗi, tinna pati o yiye. + O yehi faa mo ganndii wuro ngoo, o fanti waande, mo yalti ley leggel ngel, mo parii faa gasi, mo watti masiri makko faa mo wooɗi, mo ɓaari leggel ngel e waande ndee, nii tan mo foonndii wuro ngoo to ɲallo Amiiri’en ton jaati. + Nde Amiiri njaatigi makko oo soyninoo mo ndee, wii: +• Cuggam e surba debbo garoowo ton oo. + Amiiri oo immii, sakkitii leggel, joƴƴini mogere mum, hirsani ɗum mbaalu payɗo, ɓe njooɗii eɓe ngaajoo, Amiiri itti hootonnde mum hokki mo, kaa annditaali yalla ɗum leggel. + Ɓe ngondi e ɲallo faa hiiri, surba oo wii hootan. Jamaa oo fuu ɗowti ɗum faa anndi ɓadike waande ndee, wii: +• Njoppee kam ɗoo. +Ɓe kokki mo koyngal tew kirsaandi makko ndii, ɓe mbaynii mo, ɓe mbaylitii. + Nde leggel seli yiide ɓe ndee, naati ley leggel mum, dogi faa e debbo mawɗo oo, wii: +• Hee yimɓe ton ɓee ana caahii faa sanne! Sabi mi wallii ɓe defude tan, ɓe kokki kam koyngal mbaalu. + Debbo mawɗo oo, ɗum weli ɗum faa sanne, wii: +• Gasii. Kaa kori Amiiri yihaali ma? +O jaabii, o wii: +• Mi yaltaali ley kaatane gila njaa-mi. + Ko Amiiri warti koo, puccu mum kuu wari faa silla, Amiiri heddii ana duka: +• Hoto leggel woni? Puccu kuu annii silla, a yaltataa naa? +Leggel dogi warde faa puccu kuu silla dow mum. Inna Amiiri defi tew oo, kaa o haalani Amiiri taakallemme makko hokki mo tew oo, sabi mbaalu mum waati. + Ko ɓe ɲaami koo, Amiiri wii: +• Inna, dawol hewtike kam, ngaɗanaa kam cobbal so weetii, mi jahoowo caggal maayo. +Inna uni gawri faa waɗa cobbal tame. Nde mo tamata ndee, leggel wii: +• Accu miin duu mi tama fay so gootel. + Inna oo jaɓaali, kaa o siini. Nde inna oo hokkunoo mo ndee, mo tami ɓooɗel gootel, mo tamdi ngel e hootonnde nde Amiiri hokkunoo mo ndee. + Caggal weetii, Amiiri oo e jamaa mum ndawi caggal maayo. Fade maɓɓe lummbude maayo ngoo, Amiiri oo wii ɓe: +• Taƴen kooƴol de lummben. + Amiiri hokki homo fuu ɓoodde, gootel tusukel keddiingel ngel woni ngel leggel tamidi e hootonnde ndee, ɗum laatii ngeɗu Amiiri. Nde mo fecci ngel ndee, mo yii hootonnde ndee, mo ƴeewi faa gasi, mo tawi ɗum hootonnde makko nde mo hokki surba debbo oo jaati ndee. O wii jamaa oo: +• Accanon kam hakke, mbirfo-ɗen wuro, sabi hoore am ana naawa kam sanne, mi waawaa yaade. + Ɓe coƴƴii. Mo yaafii jamaa oo, o wii inniiko: +• Homo tami cobbal ngal? +Inna oo huli faa sanne, wii: +• Miin jaati tami. +O holli ɗum Alla, haala ngoonga; inna oo wii: +• Wallaahi mi fenataa ɗum. +Ndeen inna oo wii: +• Leggel tamii. +Amiiri oo wii: +• Inna, mi ɓaman Leggel. +inna oo yowi junngo mum dow hoore mum ana wulla, ana wiha: +• Hammadi am haanɗii. Sabi wii ɓaman Leggel. + Amiiri yehi e debbo mawɗo faa lamndoo ɗum hono watta so surba oo yalta ley leggel ngel. Debbo mawɗo oo jaabii, wii: +• O waalataa ley maggel. Horu mo, so mo yaltii fuu, kakkilaa, jawdi mawndi ana ley leggel ngel, mbaylaa ndi faa ndi laaɓa, de cumaa leggel ngel. + Nde jemma warnoo ndee, Amiiri acci faa Leggel yalti ley leggel ngel fukkii, ɗaanii. Mo warri no debbo mawɗo wiiri mo nii. Surba oo nde ɗemƴii ndee tawi jawdi mum fuu dow daago, leggel ngel sumaama; mo anndi ɗum yo golle Amiiri. + Nde weetunoo ndee, inna yii surba e jawdi ndii, o darii omo woma, omo wiya: +• Hammadi am huurtinii kaŋŋe, hammadi am huurtinii cardi. +Nii Amiiri huurtiniri mo ley galle mum. + + +Sukaaɓe rewɓe taton + Ɗum waɗiino, sukaaɓe rewɓe taton: Diko, Kummbo e Penndo. Eɓe kiira jemma faa Diko oo wii: +• Miin kaa, Alla wan mi laatoo gen moƴƴinoowo buuru Amiiri oo. +Kummbo oo duu wii: +• Miin kaa, mi laatoo gen Amiiri oo jaati ɓurani kam. +Penndo oo duu jaabii: +• Miin duu, mi laatoo gen duppoowo tew makko tan, mi ɲaama tew faa mi haara. + Amiiri wuro oo duu jemma fuu ana yiiloo ley wuro faa nana ko yimɓe wuro kaalata e mum. Tan o nani ko sukaaɓe rewɓe taton ɓee kaali. Nde weeti nden, o neli maccuɗo makko nodda ɓe ngara. Ɓe ngari, o wii ɓe pilloo ko homo fuu haalnoo. Nden o warri non: Diko oo ɓamaa jom buuru. Penndo oo duppoowo tew, Kummbo oo, Amiiri oo jaati. + Ɓe ngorri non faa Kummbo inne ɓami reedu. Nde o maati ndimu nden, o neli e Diko inne wara. Nde o warata nden, o saawi ley saaya makko ɓinngel bilel baatungel. + Diko inne wii: +• Kummbo inne, mummu gite maa, sabi so neɗɗo ana rima fuu uddan gite mum. +Kummbo inne warri non. Nde o rimi nden, Diko inne suumi suka oo pati ewa, o faɗɗi ley doginirgol, o lelni ɓinngel bilel baatungel. Kummbo inne mettaa sanne, kaa faamaali ko mawnum oo waɗi ɗum. + Ko ɓami reedu ɗiɗaɓurdu nden duu, o warri non. Kaa nden, ɓinngel ŋusuwel baatungel o waddi. Nde tataɓurdu nden duu, hayre o saawi, o waddi. + Deeɗi tati ɗi Kummbo inne rimi ɗii fuu wo ɓiɓɓe worɓe: Hammadi, Sammbo e Yero. Nde Diko inne faɗɗi ɓiɓɓe ɓee fuu, ndegoroo doginirgol ngol faa naatawa ley sardiŋe gorko mawɗo e genndum, ɓe ndimaali abada. Aranndeejo oo nde ɓe koocci ɗum ɓe kuyi ɓe mbii: +• Alla yurmike en, neldi en ɓiɗɗo. +Ɗiɗaɓo oo e tataɓo oo fuu, non ɓe miili. + Nii non ɓiɓɓe taton ɓee keddii e junngo gorko mawɗo e debbo mawɗo faa ɓe mawni, ɓe laatii jokolɓe, faa mawɓe ɓee maayi, ɓe keddii e nokku maɓɓe. + Ɲannde wootere, hammadiijo oo hooƴi malfa mum yehi lowangal. + Amiiri wuro ngoo, ɗum woni abbiiɓe jaati, oon duu yehi lowangal. Homo fuu yii lella ngaa, homo fuu enndi nga, felli nga faa homo e maɓɓe fuu sikki kaɲum tan felli nga. Nde lella ngaa saami nden, hammadiijo oo yehi faa ɓama nga, Amiiri oo duu neli maccuɗo mum hoccawa lella ngaa. Nden homo fuu wii: «Miin fiɗi nga.» Nde Amiiri oo wari yii suka jokolle oo yiɗi mo ley yonki mum sanne, kaa anndaa mo. Nde ɓe kaaldi nden, Amiiri oo wii o hooƴa lella ngaa, hokki mo nga. Ɗum weli mo sanne. Kanko duu o wii: +• Faa mi yoɓe ngal teddeengal, ngaraa ɲallanaa kam alan garoowo nokku am ley ladde. +Ɗum weli Amiiri, jaɓani mo teddeengal ngal. + Homo fuu hooti suudu mum. Hammadiijo oo narriino gorko mawɗo oo e nguurndam mum ana haala ndiyam kaaloojam e foondu haalooru. O wii sanaa o waddana Amiiri oo huunde teentiliinde nde oon woowaa yiide. Sabi teddinɗo mo warata suudu makko. + Dow sifa gorko mawɗo oo, o jokki laawol omo yaha faa o tawi: Annii ley ladde ndee ginnaaji. O wii faa o welloo fuu, ɗi keddii eɗi paɗɗa mo kaaƴe, o nootaaki. Omo yaha faa o tawi kasen goɗɗi ana njala mo, o nootaaki. Faa o yehi o ɲeɗi ndiyam kaaloojam ɗam, o nanngi foondu haalooru nduu. Ginnaaji ɗii ummii ana caaƴa sanne faa kulɓina mo. Kaa o hulaali fey, faa o warti. O lalindii faa gasi, kanko e miɲiraaɓe makko, jaɓɓaade Amiiri maɓɓe. Kaa ɓe anndaa salla abbiiɓe. + Nde Amiiri oo wardi e yimɓe mum, ɓe njaɓɓitii mo ɓe ngaajii sanne, ɓe ɲaami faa ɓe kaari o holli ɓe nokku makko, sardiŋe makko e foondu nduu e ndiyam kaaloojam ɗam. Ko foondu nduu yii ɓe ɗum, wii: +• Amiiri, ɓiɓɓe ɓee ɓiɓɓe maa! +Tan o fillorii gila nde sukaaɓe rewɓe taton ɓee mawniri, faa e lella ngaa. Tan, ɓe fuu ɓe kaaynaa, ɓe njurŋinii, ɓe mboyi, ɓe ƴeewondiri, ɓe nanngondiri juuɗe. Amiiri oo wii: +• Ngaree faa kooten. +Hammadiijo oo haalani miɲiraaɓe mum, ɓe njaɓi. Kaa Hammadi wii: +• Faa horra foondu nduu e ndiyam ɗam to tawi ton tafon. +O warri non. + O warti, o yaadi e abbiiko e miɲiraaɓe makko to inniiɓe, kam duu, ko haalanaa ɗum seyii sanne. Kaa Diko inne, nesi mum taƴi laatii waande. + + +Taali +Mi yehii wuro, baabam hokki kam lonngere ndonku-mi timminde. +Mi yehii wuro baabam, taw-mi ɓiɓɓe am ɓee fuu woɗeeɓe. +Njoƴƴin-mi jommbaajo am dow laawol, bellotooɗo fuu wiyan kuyuuja. +Leelewal ley leeso. +Mbana yahataa, mbana warataa, yawooɓe ndaɗataa mbana. +Ɓiɓɓe am ɓee fuu wo sukuɲaaɓe. +Teketol mbuubu heewi ganure (loonde mawnde). +Kaatane ley ndiyam. +Mi lummba maayo, mi lummbita maayo, mi tappa paɗe am colla ana runnda. +Getogel ɓalewel ley toggere ɓaleere. +Jabaabu +1. Kaata +2. Gelleeje +3. Njaaɓi +4. Ɓoccooɗe +5. Laawol +6. Padakaaje +7. Tuundi ley yitere +8. Gangariije +9. Ɓoye +10. Tennga ley hoore + + +Amiiri wuro lobbo ŋari sanne + Dum waɗiino, amiiri wuro wooto, o ŋarɗi faa sanne faa omo hoolii hoore makko. O wii so wanaa debbo ɓurɗo mo ŋari fuu, o ɓamataa ɗum. Yimɓe ana tewta faa ɓe njii e wuro wooto, ɓe tawi suka debbo lobbo sanne faa ana ɓuri amiiri oo ŋarɗude. Nii ɓe kaalani ɗum. Nde weeti nden, o humi puccu makko yaade ton. O tawi no wiiraa noon worri. O ɓami suka oo to abba mum, o wii o hokkan abba oo muddiije kaŋŋe sappo. Abba oo wii ɗum heɓataa ɓiyum. Amiiri oo ana terma faa o wii: +• Mi hokkete muddiije teemedere. +O jaabii: +• Heɓataa. +O wii: +• Ndeennoo ko heɓata ɓiya oo? +Abba oo jaabii, wii: +• Amaana heɓata ɓiyam oo. Miɗo ndaarde pati o tampa, pati o heyɗa, pati o ɲaanoo faa abada. +Amiiri oo wii: +• Nanii, jaɓii. +Hokki mo aadi faa abada o jippataako sooro, o yihataa naange. + Amiiri oo huurtini mo, yaadi e makko wuro mum. Faa ɗum waɗi lebbi, tan suka oo wokkiti, nii fuɗɗi wullude. Jom suudu makko lamndii mo ko o woyata, maa ko ɲakani mo e aduna. O jaabii, o wii o yeewaa. Gorko oo lamndii ko yeewtinta mo. O wii omo yiɗi tiimtorgal kaŋŋe ngal o tiimtoroo, ana yeewtina mo. + Hono naanen, wayluɓe noddaa, tafi tiimtorgal ngal, ngal ŋeɲaa kulle ladde faa ngal heewi. Ɓe ngorri noon faa ɲannde wootere, gorko oo yalti fajiri law, tan suka jokolle lobbo ŋari sanne, kaa o gariibu o walaa fay huunde. O garbinii debbo oo, hokka mo sabi Alla ko ɓuri fuu yidde e adunaaru nduu. Debbo oo jaabii: +• Ko ɓur-mi yidde e adunaaru nduu kaa yo ɓiɗɗo, kaa mi walaa. Kaa miɗo jogii tiimtorgal kaŋŋe ngal njiɗu-mi sanne, ngal goram tafani kam faa mi yeewtira. +Hono ngal, hokki mo ngal saabi Alla mo o inndi oo. + Gariibu oo yehi wuro mum`en, ana tacca seeɗa seeɗa e kaŋŋe, ana sootta, ana laatoo jom jawdi faa gasi. Omo warra ko Alla, wuro ngoo hoolii mo, hokki mo laamu. + Caggal debbo oo hokkii gariibu oo tiimtorgal ngal, gorko oo wayri yiide debbo oo ana tiimtoo. O lamndii ɗum no tiimtorgal ngal waɗi, debbo oo haalani mo no waddi e gariibu oo, gorko oo bilaa sanne faa mo wii: +• Hollam junngo ngo kokkir-ɗaa gariibu oo tiimtorgal ngal +O holli junngo makko ɲaamo, gorko oo nanngi ngo tacci ngo, seeri debbo oo, riiwii mo, mo yalta e galle mum. + Debbo oo woowaa naange, mo tampi sanne fade makko jippaade sooro ngoo, o fonndii wuro maɓɓe. Ɲalooma fuu, mo suulta ley leɗɗe kaa jemma fuu mo yahan, faa mo tampi, mo daali. + Sukaaɓe jokolɓe ɗiɗon tawi mo ley ladde, ɓe njurmii mo, ɓe lamndii mo ko foti waddude mo ɗoo, o fillanii ɓe. Ɓeen mballi mo faa mo yottoyii abbiiko. Abba oo barkini sukaaɓe jokolɓe ɓee sanne. + Gariibu mo mo sakkii tiimtorgal kaŋŋe ngal oo ana tewta debbo faa yimɓe kaalani ɗum haala debbo oo. Kaa mo anndaa salla ɗum gen kaananke cakkuɗo mo oon noon. O ƴami, o hokkaa ɗum, o huurtini ɗum. Kaa no debbo oo foti woodde, o taykaaki salla junngo mum ko taccaa. Nde kuurtungu oo dammbitii nden, gorko oo se’ini laana faa ɓe njaha wuro maɓɓe. + Debbo oo sulli sanne, sabi junngo mum yo tayngo, mo ɲaagii Alla suura mo pati yimɓe anndita mo guddo. + Saabi Alla mo gariibu oo wardi e makko oo so mo hokki ɗum tiimtorgal ngal, nde saabanii mo junngo tayngo ngoo. + Debbo oo fukkii ley jemma, o fini e baawɗe Alla, o tawi junngo ngoo dobii. + Debbo oo yettiri Laamɗo ko waɗani ɗum koo. O wondi e goriiko faa Alla hokki ɓe ɓinngel gorel, gorko oo ana horsini ngel sanne. Gorii debbo oo aranndeejo oo, taccuɗo junngo makko oo, ana yaara caggal fajiri fuu, gilla nde mo tacci junngo debbo oo ndee, faa o timmini jawdi makko, faa omo garbinoo. Wuro ngoo ittii mo e amiiraaku. Omo yaha, omo garbinoo faa mo nani haala Amiiri wuro jom jawdi oo. Fajiri law, o wari e gen amiiri oo, tawi gorko oo yaltidi e ɓinngel mum gorel ngel faa ɓe njiildoo e ley wuro fade naange wulde. + Amiiri talkinɗinɗo faa laatii gariibu oo, wari e debbo oo, wii: +• Fii sabiilillahi! Hokkam ko ɓur-ɗaa yiɗude e adunaaru nduu fuu. +Debbo oo jaabii, wii: +• Subahaanahuu! Ko ɓur-mi fuu yiɗude e adunaaru nduu, yo ɓinngel am gorel, ngel nee abba mum yaltidii e mum, kaa miɗo jogii goje kaŋŋe ɗe goram tafani kam faa mi yeewtira, miɗo yiɗi ɗe sanne. +Debbo oo hooƴi ɗe, hokki mo. Nde mo wari faa mo jippoo sooro ngoo ndee, o hawri e gorko oo. Oon wii mo: +• Yaa yoppoy ko kooƴu-ɗaa ɗum, a gujjo. +Debbo oo jaabii: +• A wihaay miin hokku maa naa? +Ndeen o fillanii gorko oo no ɓe ngaddi. Ɗum welaali gorko oo sanne, kaa mo miccitii no mo sakkiraa tiimtorgal kaŋŋe ngal nii e junngo gen kaananke oo. O yamiri hoorɓe loota mo, kokka mo kaddule kaɲum e ko mo ɲaama, kanko kaa mo yalti. + Gorko koɗo oo ana ɲaama, ana ƴeewa debbo oo, laatii hono annditii ɗum nii, kaa omo anndi oon junngo mum ko taccaa. + Mo lamndii debbo oo yalla ana anndi debbo mo junngo mum taccaa, gen amiiri kiiɗɗo naa? Debbo oo duu wii: +• Aɗa nanndani kam e goram aranndeejo, kaa oon kaa wanaa gariibu, o kaananke wuro. +Gorko jaabii, wii: +• Miin noon +Debbo oo duu wii kaɲum noon! Kaa Alla dobii junngo mum ngoo. + Ɓe ɗiɗon fuu ɓe kaayɗinaa, ɓe mbemmbaa, ɓe tawi ɗum Alla fodi. Ko goriiko oo warti koo, mo fillanii ɗum no ɗum laatirii. Gorko oo wii mo: Miin duu, miin woni gariibu mo cakku-ɗaa tiimtorgal kaŋŋe oo. Homo fuu annditi banndum, simtiri, anndi Alla waawi. + Ndeen amiiri gorii debbo oo, wii o ɲiɓanee sooro hono ngo mum ngoo, o naati. Wii o suɓoo debbo mo o yiɗi ley wuro ngoo fuu, ɓamani mo, ɓe ngondi faa abada. + +Puri +11. Mi hawrii e pooli: wooturu nduu ana ardii ɗiɗi, wooturu nduu ana hetti caggal ɗiɗi, wooturu nduu ana tummbii hakkunde ɗiɗi. Hono foti ɗii pooli? +Miɗe yaha luumo, pantu-mi esam, o neldi kam buuɗi makko teemedere, o wii: Mi soodana mo daabaaji: bey, baali e nay faa daabaaji ɗii kiɓɓa teemedere. Njaa-mi luumo, taw-mi nagge fuu buuɗi joy, mbaalu fuu mbuuɗu, bey joy fuu mbuuɗu. Hono ngaɗan-mi faa teemedere ndee heɓa daabaaji teemedere, pati mbuuɗu fuu heddoo? + +Jabaabu: +12. Pooli ɗii yo tati +Mi soodan nay sappo, laatoo buuɗi debe e sappo, baali debe laatoo buuɗi debe, bey debe e sappo laatoo buuɗi sappo. +No debbo gooto foti yiɗude adunaaru + Waɗiino e jamaanuuji debbo gooto, wii so rimi ɓiɗɗo ɓurɗo ɗum ŋarɗude fuu o faɗɗayan ɓinngel ngel ladde. Alla waɗi o rimi ɓiɗɗo debbo, yimɓe fuu mbii ɓiɗɗo oo ana ɓuri inna oo ŋarɗude. Inna oo acci faa suka oo ƴoƴi. Ɲannde wootere omo yaha teenoyde, o naɓi cukalel ngel ladde. Caggal o tilike teenude o joƴƴini cukalel ngel ley lekki bannge waande, o wii ngel dooma mo, jooni o waran. Nii o hooti cuuɗi, o yoppi ngel ton. + Cukalel ngel doomi faa tampi engel wulla. Gorko gooto ana waɗɗii ngeelooba, wari tawi cukalel ngel ana wulla, o lamndii ngel, ko saabi so engel wulla? Ngel wii mo: +• A yiyanaali kam ton innam naa? +Gorko oo wii ngel: +• Hoto inna maa jeyaa? +Ngel jaabii gorko oo: +• Mi anndaa! + Ngel yurminii gorko oo faa sanne, nii o ɓami ngel, o waɗɗini ngel dow ngeelooba makko. Tawi suka oo inna mum haɓɓaniino ɗum ceede tati e keeci mum. Suka oo ɗo waɗɗii dow ngeelooba ngaa, hunti ceede mum ɗee haɓɓi e samme ngeelooba gorko oo, eɓe njaha faa ɓe njottii ngenndi ngootiri, o naɓi suka oo to Amiiri ngenndi ndii, gorko oo fillanii yimɓe ngenndi ndii no o hoocciri suka oo ley ladde. Nde gorko oo wii faa witta nden: Suka oo heddii ana wulla, wii kaɲum jey ngeelooba ngaa. Haala kaa laatanii yimɓe ngenndi ɓee wemmbere. Ɗum laatii sariya hakkunde maɓɓe. Yimɓe ngenndi ɓee mbii suka oo holla maande mum. Suka oo wii: +• Ceede tati ana kaɓɓii e samme ngeelooba ngaa, miin jey nga. +Gorko oo hunii waatii so ceede tati tawaama e samme ngeelooba ngaa fuu, o harminii nga faa yeeso Alla. Nde yimɓe ngenndi ɓee ƴeewunoo nden, tawi ceede tati ana kaɓɓii e samme magga. Yimɓe ɓee mbii: +• Suka oo ngoongoto, kaɲum jey ngeelooba ngaa. +Nii gorko oo jippii hokki suka oo ngeelooba ngaa, wittiri koyɗe ɓole ɓernde mum ana woya. + Suka heddii e junngo Amiiri faa o laatii surba debbo, sakiraaɓe makko anndaaka. Amiiri ngenndi ndii huurtini suka oo, sabi kaɲum duu ɓooyii heɓaali ɓiɗɗo. Ko o ɓami suka oo koo kaɲum duu ɓooyi rimaali, kaa ana jogii korɗo mum debbo kaamilɗo, o wii ɗum so rimii fuu hokka mo ɓinngel mum ngel, de ko yiɗi fuu waɗa ley galle ton - korɗo debbo oo jaɓani mo. Kanko suka oo lewru fuu o ɓama licce o watta ley reedu makko faa korɗo debbo oo maati ndimu mum. Yehi rimoy to suka debbo oo, o lootii faa o laaɓi. Suka debbo oo jooɗii ley ƴiiƴam ɗam gere ɓinngel ngel, o neli Amiiri haalanee o rimii o heɓii ɓiɗɗo gorko. + Amiiri e jamaa mum fuu kuyi faa sanne, sabu abada o heɓaali ɓiɗɗo. Ɲannde wootere omo womina ɓinngel ngel fuu, o wii: +• Coo wajjere, coo wajarde, inna maa waawi bonnde teetii joom ngeelooba mum, teetii ma aan duu inna maa. +Tawi jokko Amiiri gooto warii faa yara ndiyam, nani haala kaa tan, wii debbo oo: +• Eyyo! Ɓiɗɗo oo wanaa ɓiya naa? + Debbo oo jaabii, wii mo: +• Gilla Amiiri laatii giɗo maa a yarii cobbal makko njumndi ngal na? + Gorko oo gila nani haala cobbal ngal tan, yeggiti haala ɓinngel ngel. O wii: +• Abada o yaraali ngal cobbal. +Debbo oo naati ley suudu yaltini hokki mo, o yari. Debbo oo wii mo o loota hunduko makko pati Amiiri oo anndita. O looti hunduko makko, debbo oo wii: +• Laaɓaali. Sabu ɗemngal maa ngal ana oolɗi, waddu mi heefene faa laaɓa pati Amiiri anndita. + Nii o ɓattii debbo oo nanngi ɗemngal ngal tacci. Ƴiiƴam heddii ana jooroo. Gorko oo fonndii bolongal Amiiri, nde o yottii ndee, yimɓe ngonnooɓe ɗoon ɓee fuu immii cakkitii o faa lamndoo mo, nii o sappii debbo Amiiri oon. Debbo oo lamndaa, jaabii ɓe, wii kaɲum kaa yiino omo dardii e jom`en pucci, kaa anndaa ko ɓe kaaldi, tawan ɓeen tacci ɗemngal makko so ndilli. Wakkati oon fuu Amiiri wii: +• Pucci kumee, pucci kumaa. +Wii ɓe tewɲa jom`en pucci ɓee. + Jamaa oo tewɲi henndu, njiiloyii faa tampi ɓe njiyaali fay huunde, nii ɓe ngarti. + + + +Taali tacciti: +13. Debbo lobbo mo ɓamataake +Ɓiɓɓe am ɓee fuu ɓe kumitirngol gootol +Kaɓɓu-mi puccu am ley suudu laaci makku ana yalti sella +Mi yehii wuro baabam, taw-mi yimɓe fuu ana njala. +Jabaabu: +14. Leelewal +Piisirɗi + + +Curki +Liyeewa pernga (haabu) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/docs/help/guides/walkthrough/__index.txt b/developer/docs/help/guides/walkthrough/__index.txt new file mode 100644 index 0000000000..2bb307d6f9 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/__index.txt @@ -0,0 +1,13 @@ +00-introduction.md +01-creating-keyboard-project.md +02-designing-desktop-layout.md +03-creating-desktop-layout.md +04-using-debugger.md +05-designing-touch-layout.md +06-creating-touch-layout.md +07-writing-keyboard-documentation.md +08-preparing-keyboard-package.md +09-distributing-keyboard-package.md +10-generating-lexical-model.md +11-installing-lexical-model.md +glossary.md diff --git a/developer/docs/help/guides/walkthrough/dag-short-wl.txt b/developer/docs/help/guides/walkthrough/dag-short-wl.txt new file mode 100644 index 0000000000..53968e2c8b --- /dev/null +++ b/developer/docs/help/guides/walkthrough/dag-short-wl.txt @@ -0,0 +1,25 @@ +ka 93 +o 63 +ni 55 +daa 51 +maa 28 +ti 23 +n 17 +a 16 +bɛ 14 +nti 12 +di 12 +dii 10 +yi 9 +ba 9 +so 8 +na 7 +m 7 +la 7 +jɔn 7 +chɛ 7 +pam 6 +kpe 6 +be 6 +ŋɔ 5 +dol’ 2 diff --git a/developer/docs/help/guides/walkthrough/glossary.md b/developer/docs/help/guides/walkthrough/glossary.md new file mode 100644 index 0000000000..66375d0152 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/glossary.md @@ -0,0 +1,203 @@ +--- +title: Glossary of Key Terms +--- + +## Core Software & Tools + +### Keyman Developer + +Keyman Developer is a powerful tool you can use to create custom keyboards optimized to type in any language you choose. Keyboards created with Keyman Developer can be used on Windows, macOS, Linux, iOS, Android, and the web. The Keyman Developer IDE (integrated development environment) is currently Windows-only, however the command line tools it uses can run on other platforms (such as Linux and macOS). + +### Keyman + +The application that allows users to actually use keyboards created with Keyman Developer. Available on Windows, macOS, Linux, iOS, Android, and the web. Distinguished from Keyman Developer by its regular (not faded) app icon. + +### Keyboard Editor + +The primary tool within Keyman Developer used to design and program keyboard layouts, accessible through both drag-and-drop visual design and direct source code editing. + +### Package Editor + +A tool within Keyman Developer used to bundle keyboard files, fonts, documentation, and other resources into a distributable package file (.kmp). + +### Debugger + +An interactive tool in Keyman Developer that allows keyboard authors to test keyboard rules, step through complex logic, inspect store contents, and examine context, deadkey state, and output at each point during keyboard operation. + +## Keyboard Components & Concepts + +### Keyboard Project + +A complete project containing all files and resources needed to develop, test, and distribute a keyboard. Organized through a .kpj project file. + +### Keyboard Layout + +An arrangement of keys (either physical keys on a physical keyboard or key images on the screen of a touch device) allowing a set of characters to be typed. A layout is composed of one or more layers, which are accessed by modifier keys (such as Shift or Alt). + +### Keyboard Layer + +A subset of the keys in a keyboard layout. This subset is accessed by a modifier key. For example, holding down the Shift key on a physical keyboard gives you access to the Shift layer. Similarly, tapping the “!#1” key on a touch layout presents the Numeric layer. + +### Desktop Layout + +A keyboard layout designed for use on desktop/laptop computers with physical keyboards (Windows, macOS, Linux). It is also used when a physical keyboard is attached to a touch device. Stored in .kmn files. + +### Visual Keyboard / On Screen Keyboard + +A graphical representation of the keyboard layout that shows users which keys produce which characters. Files with .kvks extension. + +### Touch Layout + +A keyboard layout designed for use on touchscreen devices like smartphones and tablets (iOS and Android). Created using the touch layout editor and stored in .keyman-touch-layout files. + +### Keyboard Package + +A bundled distribution file (.kmp) that contains one or more keyboards along with fonts, documentation, and on-screen keyboard files, ready for installation on user devices. + +### Lexical Model Package + +A bundled distribution file (.kmp) that contains a lexical model, ready for installation on user devices. + +### Keyboard Authors + +Individuals or organizations who create custom keyboard layouts using Keyman Developer. + +## Lexical Models & Predictive Text + +### Lexical Model + +A language model that powers predictive text and autocorrect functionality for a keyboard. Also called a “dictionary” in Keyman apps. It uses word lists to suggest completions, corrections, and properly accented variants as a user types. + +### Wordlist + +A list of words in a language, typically stored in a tab-separated values (.tsv) file, used as the foundation for creating a lexical model. To be effective as a source for suggesting words, each word should have a number indicating its relative frequency in normal usage. This is often accomplished by counting words in a large text sample. + +## Programming Concepts + +### Deadkey + +An invisible placeholder character used in keyboard programming that doesn't appear on screen but can be matched by future rules. Deadkeys allow complex input sequences, such as distinguishing between typing an apostrophe twice for a quote versus once before a vowel for an accent. Keyman supports up to 65,534 unique deadkeys per keyboard. + +### Context + +The text or characters that precede the current cursor position, which keyboard rules can examine to determine appropriate output. + +### Rule + +A programming statement in Keyman keyboard language that transforms inputs to outputs, following the pattern: context + keystroke > output. + +### Store + +A named variable in Keyman keyboard language that holds a set of characters or deadkeys for use in keyboard rules. + +### Group + +A collection of related keyboard rules organized together for processing keystrokes or manipulating context. + +## Language & Encoding + +### BCP 47 Tags + +Language identification codes following the Best Current Practice 47 standard (e.g., "en" for English, "str-Latn" for Straits Salish in Latin script). These tags consist of: + +- **Language subtag**: ISO 639-1 (2-letter) or ISO 639-3 (3-letter) code +- **Script subtag** (optional): ISO 15924 4-letter code for writing system (e.g., "Latn" for Latin, "Cans" for Canadian Aboriginal Syllabics) +- **Region subtag** (optional): ISO 3166-1 alpha-2 country code or UN M49 region code + +Keyman uses BCP 47 tags to provide language metadata, facilitate keyboard searches, and associate keyboards with operating system language settings. + +### Unicode + +The universal character encoding standard that Keyman keyboards fully support, allowing access to characters from any writing system. + +## File Types + +### .kpj (Keyman Project) + +The main project file that contains references to all components: keyboards, models, and packages. Used to organize and manage the entire keyboard development project. + +### .kmn (Keyman Source) + +A plain text keyboard source file that contains all the code and rules for a Keyman keyboard. This is the human-readable programming file that keyboard authors edit. + +### .kvks (Keyman Visual Keyboard Source) + +The source file for an on-screen keyboard, created in Keyman Developer's visual keyboard editor. + +### .keyman-touch-layout + +A JSON format file that describes a keyboard layout specifically for touch devices (phones and tablets). + +### .model.ts (Model TypeScript) + +A TypeScript source file that defines a lexical model, specifying the format, word-breaking rules, and source files (wordlists) to use for predictive text. + +### .tsv (Tab-Separated Values) + +A text file containing a list of words, one per line, with an optional tab-separated frequency count, used as source data for creating a lexical model. + +### .kps (Keyman Package Source) + +A package source file created in the Package Editor that specifies which files (keyboards, fonts, documentation) should be included in a distributable keyboard package or which lexical model files should be included in a distributable lexical model package. + +### .kmx (Keyman Compiled Keyboard) + +A compiled binary keyboard file created from a .kmn source file. Used by Keyman on Windows, macOS, and Linux. This is the file used by the Keyman program on the user’s computer to provide keyboard functionality on physical keyboards. + +### .kvk (Compiled Keyman Visual Keyboard) + +A compiled on-screen keyboard file that shows the visual layout of a keyboard. + +### .js (Compiled Keyboard JavaScript) + +A JavaScript file created from a .keyman-touch-layout source file, used by Keyman apps on touch devices to provide touch keyboard functionality. + +### .model.js (Model JavaScript) + +The compiled JavaScript file created from a .model.ts source file, used by Keyman apps to provide predictive text functionality. + +### .kmp (Keyman Package) + +A compiled, distributable package file that bundles keyboards, fonts, documentation, and other resources into a single installer. This is what end users download and install. + +## Distribution & Community + +### Keyman Community Forum + +An online forum ([community.software.sil.org/c/keyman](http://community.software.sil.org/c/keyman)) where keyboard authors can ask questions, share knowledge, and get support from other developers. + +### Keyman GitHub Repository + +The open-source code repository ([github.com/keymanapp](http://github.com/keymanapp)) where Keyman software is developed and where users can contribute keyboards, report bugs, and submit improvements. + +[**help.keyman.com**](https://help.keyman.com) + +The comprehensive online documentation site for Keyman Developer, containing language references, tutorials, guides, and API documentation. + +## Advanced Concepts + +### Base Layout + +The keyboard layout of the system when Keyman is not active. For example, the base layout might be the QWERTY (US English) layout, the AZERTY (French) layout, or a Thai layout, depending on the settings of the device. + +### Mnemonic Layout + +A keyboard layout where keys are identified by the character produced after the [base layout](#toc-base-layout) is applied, rather than by their physical position. For example, on a US English (QWERTY) keyboard the “A” key is directly to the right of the Caps Lock key and the “Q” key is above it, but on a French (AZERTY) keyboard the “Q” key is directly to the right of the Caps Lock key and the “A” key is above it. If a Keyman keyboard has `&mnemoniclayout` enabled, the rules for “A” will take the base layout into account and respond to the “A” key, even though it is a different physical key on the two keyboards. + +Note that some keyboards in the Keyman keyboards repository use the term “mnemonic” in the title or description to indicate that the characters (usually of a non-Latin script) are assigned to keys according to their correspondence with the US English (QWERTY) layout. For example, the Arabic “beh” character might be assigned to the location of the “B” on the QWERTY keyboard. + +### Positional Layout + +A keyboard layout where keys are identified by their physical position on the keyboard rather than the character displayed on the keycap. For example, the "Z" position on a US keyboard corresponds to the "Y" position on a German keyboard. + +### Transient Language Profiles + +Custom language profiles in Windows (limited to 4) for languages that Windows doesn't have built-in support for, automatically managed when installing keyboards with custom BCP 47 tags. + +### Word Breaker + +An algorithm that determines where word boundaries occur in running text, essential for lexical models. Different languages require different word-breaking rules (e.g., space-separated vs. no obvious breaks in East Asian scripts). + +--- + +*This glossary is based on the Keyman Developer General Tutorial and official Keyman documentation. For the most current information, visit [help.keyman.com](http://help.keyman.com).* \ No newline at end of file diff --git a/developer/docs/help/guides/walkthrough/images/add-language.png b/developer/docs/help/guides/walkthrough/images/add-language.png new file mode 100644 index 0000000000..c2f1c88803 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/add-language.png differ diff --git a/developer/docs/help/guides/walkthrough/images/add-longpress.png b/developer/docs/help/guides/walkthrough/images/add-longpress.png new file mode 100644 index 0000000000..2043fbbbb7 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/add-longpress.png differ diff --git a/developer/docs/help/guides/walkthrough/images/characters-in-comments.png b/developer/docs/help/guides/walkthrough/images/characters-in-comments.png new file mode 100644 index 0000000000..2e53863192 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/characters-in-comments.png differ diff --git a/developer/docs/help/guides/walkthrough/images/charmap-to-text.png b/developer/docs/help/guides/walkthrough/images/charmap-to-text.png new file mode 100644 index 0000000000..7bab7d6054 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/charmap-to-text.png differ diff --git a/developer/docs/help/guides/walkthrough/images/charmap.png b/developer/docs/help/guides/walkthrough/images/charmap.png new file mode 100644 index 0000000000..15c9ca9169 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/charmap.png differ diff --git a/developer/docs/help/guides/walkthrough/images/code-tab.png b/developer/docs/help/guides/walkthrough/images/code-tab.png new file mode 100644 index 0000000000..2bf0300101 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/code-tab.png differ diff --git a/developer/docs/help/guides/walkthrough/images/copy-wordlist.png b/developer/docs/help/guides/walkthrough/images/copy-wordlist.png new file mode 100644 index 0000000000..bfbc99e76f Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/copy-wordlist.png differ diff --git a/developer/docs/help/guides/walkthrough/images/debugger-output.png b/developer/docs/help/guides/walkthrough/images/debugger-output.png new file mode 100644 index 0000000000..be565e0b5e Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/debugger-output.png differ diff --git a/developer/docs/help/guides/walkthrough/images/distribution-tab.png b/developer/docs/help/guides/walkthrough/images/distribution-tab.png new file mode 100644 index 0000000000..2b796a612c Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/distribution-tab.png differ diff --git a/developer/docs/help/guides/walkthrough/images/history-md-file.png b/developer/docs/help/guides/walkthrough/images/history-md-file.png new file mode 100644 index 0000000000..5e5bc029fb Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/history-md-file.png differ diff --git a/developer/docs/help/guides/walkthrough/images/keyboard-model-device.png b/developer/docs/help/guides/walkthrough/images/keyboard-model-device.png new file mode 100644 index 0000000000..ed6b5807e3 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/keyboard-model-device.png differ diff --git a/developer/docs/help/guides/walkthrough/images/keyboards-tab.png b/developer/docs/help/guides/walkthrough/images/keyboards-tab.png new file mode 100644 index 0000000000..d36945796b Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/keyboards-tab.png differ diff --git a/developer/docs/help/guides/walkthrough/images/keyman-developer-icon.png b/developer/docs/help/guides/walkthrough/images/keyman-developer-icon.png new file mode 100644 index 0000000000..29801e83c3 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/keyman-developer-icon.png differ diff --git a/developer/docs/help/guides/walkthrough/images/keyman-icon.png b/developer/docs/help/guides/walkthrough/images/keyman-icon.png new file mode 100644 index 0000000000..88ecb27608 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/keyman-icon.png differ diff --git a/developer/docs/help/guides/walkthrough/images/layer-selection.png b/developer/docs/help/guides/walkthrough/images/layer-selection.png new file mode 100644 index 0000000000..2ec89966f3 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/layer-selection.png differ diff --git a/developer/docs/help/guides/walkthrough/images/longpress-fields.png b/developer/docs/help/guides/walkthrough/images/longpress-fields.png new file mode 100644 index 0000000000..9fb0271df9 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/longpress-fields.png differ diff --git a/developer/docs/help/guides/walkthrough/images/new-lexical-model.png b/developer/docs/help/guides/walkthrough/images/new-lexical-model.png new file mode 100644 index 0000000000..a9590c624d Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/new-lexical-model.png differ diff --git a/developer/docs/help/guides/walkthrough/images/new-longpress-key.png b/developer/docs/help/guides/walkthrough/images/new-longpress-key.png new file mode 100644 index 0000000000..a1bd60dbed Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/new-longpress-key.png differ diff --git a/developer/docs/help/guides/walkthrough/images/new-project-dialog.png b/developer/docs/help/guides/walkthrough/images/new-project-dialog.png new file mode 100644 index 0000000000..5bd61d2e5b Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/new-project-dialog.png differ diff --git a/developer/docs/help/guides/walkthrough/images/notepadpp-case.png b/developer/docs/help/guides/walkthrough/images/notepadpp-case.png new file mode 100644 index 0000000000..b891a0637b Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/notepadpp-case.png differ diff --git a/developer/docs/help/guides/walkthrough/images/notepadpp-regex.png b/developer/docs/help/guides/walkthrough/images/notepadpp-regex.png new file mode 100644 index 0000000000..e5b62d0180 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/notepadpp-regex.png differ diff --git a/developer/docs/help/guides/walkthrough/images/primerprep-input.png b/developer/docs/help/guides/walkthrough/images/primerprep-input.png new file mode 100644 index 0000000000..ef46c91e90 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/primerprep-input.png differ diff --git a/developer/docs/help/guides/walkthrough/images/primerprep-start.png b/developer/docs/help/guides/walkthrough/images/primerprep-start.png new file mode 100644 index 0000000000..3564f38df9 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/primerprep-start.png differ diff --git a/developer/docs/help/guides/walkthrough/images/primerprep-with-words.png b/developer/docs/help/guides/walkthrough/images/primerprep-with-words.png new file mode 100644 index 0000000000..ce7e75cc6f Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/primerprep-with-words.png differ diff --git a/developer/docs/help/guides/walkthrough/images/shift-layer.png b/developer/docs/help/guides/walkthrough/images/shift-layer.png new file mode 100644 index 0000000000..b8c86ff08a Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/shift-layer.png differ diff --git a/developer/docs/help/guides/walkthrough/images/test-keyboard-browser-display.png b/developer/docs/help/guides/walkthrough/images/test-keyboard-browser-display.png new file mode 100644 index 0000000000..5243a8939b Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/test-keyboard-browser-display.png differ diff --git a/developer/docs/help/guides/walkthrough/images/test-keyboard-browser.png b/developer/docs/help/guides/walkthrough/images/test-keyboard-browser.png new file mode 100644 index 0000000000..2925a71086 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/test-keyboard-browser.png differ diff --git a/developer/docs/help/guides/walkthrough/images/test-lexical-model-k.png b/developer/docs/help/guides/walkthrough/images/test-lexical-model-k.png new file mode 100644 index 0000000000..99aa345043 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/test-lexical-model-k.png differ diff --git a/developer/docs/help/guides/walkthrough/images/test-lexical-model-setup.png b/developer/docs/help/guides/walkthrough/images/test-lexical-model-setup.png new file mode 100644 index 0000000000..645e44398d Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/test-lexical-model-setup.png differ diff --git a/developer/docs/help/guides/walkthrough/images/test-longpress.png b/developer/docs/help/guides/walkthrough/images/test-longpress.png new file mode 100644 index 0000000000..c9a8126d7b Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/test-longpress.png differ diff --git a/developer/docs/help/guides/walkthrough/images/u-0254.png b/developer/docs/help/guides/walkthrough/images/u-0254.png new file mode 100644 index 0000000000..6c9f534239 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/u-0254.png differ diff --git a/developer/docs/help/guides/walkthrough/images/unicode-character-value.png b/developer/docs/help/guides/walkthrough/images/unicode-character-value.png new file mode 100644 index 0000000000..fc3c96b3c6 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/unicode-character-value.png differ diff --git a/developer/docs/help/guides/walkthrough/images/windows-save-txt.png b/developer/docs/help/guides/walkthrough/images/windows-save-txt.png new file mode 100644 index 0000000000..975733e372 Binary files /dev/null and b/developer/docs/help/guides/walkthrough/images/windows-save-txt.png differ diff --git a/developer/docs/help/guides/walkthrough/index.md b/developer/docs/help/guides/walkthrough/index.md new file mode 100644 index 0000000000..20095f23f5 --- /dev/null +++ b/developer/docs/help/guides/walkthrough/index.md @@ -0,0 +1,47 @@ +--- +title: Keyman Developer Walkthrough +--- + +## Overview + +This walkthrough will give you a basic overview of Keyman Developer’s keyboard development and packaging features. + +Some tutorials seek to give the reader detailed step-by-step instructions to produce a specific result. The focus is on learning the tool and how to use it. All decisions about what to do with the tool are provided by the tutorial. + +Other tutorials seek to present a series of topics and then invite readers to consider how these apply to their own data. + +This walkthrough attempts to provide both tutorial approaches. For each topic in the [Table of Contents](#toc-table-of-contents), the first section of that topic will provide a step-by-step guide to producing a keyboard for the Dagbani language. Subsequent sections under that topic will give other examples and discuss alternative approaches that readers can consider for their own data. + + +To begin the "Step-by-Step" tutorial, start with the [Introduction](00-introduction). + +## Table of Contents + + +[Introduction](00-introduction) + +[Creating a Keyboard Project](01-creating-keyboard-project) + +[Designing a Desktop Layout](02-designing-desktop-layout) + +[Creating a Desktop Layout](03-creating-desktop-layout) + +[Using the Debugger](04-using-debugger) + +[Designing a Touch Layout](05-designing-touch-layout) + +[Creating a Touch Layout](06-creating-touch-layout) + +[Writing Keyboard Documentation](07-writing-keyboard-documentation) + +[Preparing a Keyboard Package](08-preparing-keyboard-package) + +[Distributing a Keyboard Package](09-distributing-keyboard-package) + +[Generating a Lexical Model](10-generating-lexical-model) + +[Installing a Keyman Lexical Model](11-installing-lexical-model) + +[Glossary of Key Terms](glossary) + + diff --git a/developer/docs/help/guides/walkthrough/walkthrough.css b/developer/docs/help/guides/walkthrough/walkthrough.css new file mode 100644 index 0000000000..f1027498af --- /dev/null +++ b/developer/docs/help/guides/walkthrough/walkthrough.css @@ -0,0 +1,16 @@ +.walkthrough-navigation { + display: block; + clear: both; + background: #eeeeee; + border-radius: 8px; +} + +.walkthrough-navigation::before { + content: "Keyman Developer Walkthrough"; + display: block; + background: #cccccc; + border-radius: 8px 8px 0 0; + padding: 6px 10px 6px; + font-size: 10pt; + margin-bottom: 8px; +} \ No newline at end of file diff --git a/developer/docs/help/reference/file-types/kps.md b/developer/docs/help/reference/file-types/kps.md index ef4095d9ae..5f2415a40c 100644 --- a/developer/docs/help/reference/file-types/kps.md +++ b/developer/docs/help/reference/file-types/kps.md @@ -19,9 +19,115 @@ Distributed with keyboard: ## File format +A keyboard package file contains one or more keyboards, along with readme files, +fonts (if your keyboard requires a custom font), and any other files you wish to +include. You should create a package file to bundle your keyboard with fonts and +help into a simple, single file that is easy for an end-user to install. + +A lexical model package file contains a single lexical model, optionally also +fonts and/or documentation. + +In addition to your own files, the package will contain a metadata file named +"kmp.json", which lists the details Keyman requires for installation. +The package file is a ZIP compatible archive. + +> [!Tip] You can distribute keyboards and lexical models in package files, but +> you can't include both in the same package file. + The optional `` section of the file can be included to customise the text in the bootstrap installer. The default strings are found in the file: [strings.xml](https://github.com/keymanapp/keyman/blob/stable-14.0/windows/src/desktop/setup/locale/en/strings.xml). You can add your own strings for a given package which are used when compiling as a bundled installer. + +#### Keyman for Windows + +Keyman for Windows can install keyboard package files, including installing +fonts, creating Start Menu shortcuts, and adding appropriate registry entries +for uninstallation. + +On Windows, the context menu for a package file has one additional entry: +"Install". + +#### Keyman for macOS + +Keyman for macOS can install package files with fonts and keyboards, and +shortcuts in the package will be available through the keyboard's entry in +Keyman Configuration. + +#### Keyman for Linux + +Keyman for Linux can install package files with fonts and keyboards. + +#### Keyman for Android and Keyman for iPhone and iPad + +Keyman mobile applications can install the same package files as Keyman for +Windows; the package must contain a touch-compatible keyboard (keyboard file +with a .js extension). + +## Package file contents + +A package can have a variety of different files contained within. The +following files and file types are recognized by the package installer: + +\*.kmx (Keyman for Windows, Linux, and macOS only) +: Keyboard files. Each of these will be installed. Keyman + Configuration will not allow installation or uninstallation of a + single keyboard from a package. They will always be treated as a + group for installation and uninstallation. + +\*.kvk (Keyman for Windows, Linux, and macOS only) +: On Screen Keyboard files, associated with each keyboard file. + +\*.js (mobile only) +: Touch layout Keyboard files. When Keyman mobile applications install + a keyboard package, all included keyboards will be installed as a + group. With Keyman Developer 10+, the keyboard version information is + in kmp.json, and no longer within the JS file names. + +welcome.htm +: Introductory help for the keyboard, HTML format. This will normally + be displayed when the package is installed by the user, and is also + the entry point for help when accessed via Keyman's help system or + Keyman Configuration. + +readme.htm +: Displayed before a package is installed, together with brief + metadata about the package, to allow the user to determine if they + wish to continue installation of the package. + +kmp.inf (required by Keyman 9 and earlier versions) +: A Windows .ini format file that lists each of the files in the + package, together with metadata. + +kmp.json +: A JSON format file containing metadata for the keyboard package such + as package version, keyboard versions, and listing each of the files + in the package. For more explanation of the structure of the JSON + file, please read the [metadata](metadata) documentation. + +\*.ttf, \*.otf, \*.ttc +: Truetype font files that will be installed with the package, and + uninstalled when the package is removed. On mobile, these fonts will + be available only within the Keyman app and the on-screen-keyboard, + not in other apps. + +## Share the package file + +> [!TIP] +> Read [File Layout](../file-layout) to know which files to include or exclude in the project folder. + +The best way to distribute a package is to distribute it through Keyman Cloud, +which makes it available on keyman.com and in the Keyboard Download interface +inside the Keyman apps: + +* [Share a keyboard package](/developer/keyboards) +* [Share a lexical model package](/developer/lexical-models) + +It is also possible to share a .kmp package through other means. Once the +keyboard package .kmp file is created, you can share it via external storage +devices (USB drive, SD card, etc). You can also share the package file via a +cloud storage system (Google Drive, Dropbox or similar service), then share the +link to your device via text, note or email. Alternatively, you can upload the +.kmp file to a public facing website. diff --git a/developer/src/kmc-model/src/lexical-model-compiler.ts b/developer/src/kmc-model/src/lexical-model-compiler.ts index 54b50ba503..9e0a03611a 100644 --- a/developer/src/kmc-model/src/lexical-model-compiler.ts +++ b/developer/src/kmc-model/src/lexical-model-compiler.ts @@ -182,6 +182,7 @@ export class LexicalModelCompiler implements KeymanCompiler { const sources: string[] = modelSource.sources.map(function(source) { return new TextDecoder().decode(callbacks.loadFile(callbacks.path.join(sourcePath, source))); }); + func += `globalThis.exports = globalThis.exports ?? {};\n`; func += this.transpileSources(sources).join('\n'); func += `LMLayerWorker.loadModel(new ${modelSource.rootClass}());\n`; break; diff --git a/developer/src/kmc-model/test/compile-model.tests.ts b/developer/src/kmc-model/test/compile-model.tests.ts index 5c6a8ab104..ac7baa373e 100644 --- a/developer/src/kmc-model/test/compile-model.tests.ts +++ b/developer/src/kmc-model/test/compile-model.tests.ts @@ -19,6 +19,7 @@ describe('LexicalModelCompiler', function () { 'example.qaa.wordbreaker', 'example.qaa.joinwordbreaker', 'example.qaa.scriptusesspaces', + 'example.qaa.custom', ]; for (const modelID of MODELS) { @@ -37,7 +38,11 @@ describe('LexicalModelCompiler', function () { assert.isFalse(compilation.hasSyntaxError, 'model code had syntax error'); assert.isNull(compilation.error, `compilation error: ${compilation.error}`); - assert.equal(compilation.modelConstructorName, 'TrieModel'); + if(modelID == 'example.qaa.custom') { + assert.isNull(compilation.modelConstructorName); + } else { + assert.equal(compilation.modelConstructorName, 'TrieModel'); + } }); } }); diff --git a/developer/src/kmc-model/test/fixtures/example.qaa.custom/ExampleCustomModel.ts b/developer/src/kmc-model/test/fixtures/example.qaa.custom/ExampleCustomModel.ts new file mode 100644 index 0000000000..6cd95e8a35 --- /dev/null +++ b/developer/src/kmc-model/test/fixtures/example.qaa.custom/ExampleCustomModel.ts @@ -0,0 +1,25 @@ +import { LexicalModelTypes } from '@keymanapp/common-types'; + +export class ExampleCustomModel implements LexicalModelTypes.LexicalModel { + configure(capabilities: LexicalModelTypes.Capabilities): LexicalModelTypes.Configuration { + return { + leftContextCodePoints: 16, + rightContextCodePoints: 0, + wordbreaksAfterSuggestions: false, + } + } + + languageUsesCasing: boolean = true; + + predict(transform: LexicalModelTypes.Transform, context: LexicalModelTypes.Context): LexicalModelTypes.Distribution { + if(transform.deleteLeft == 0 && context.left.endsWith('te') && transform.insert == 'h') { + return [ + { p: 0.3, sample: { displayAs: 'the', transform: { deleteLeft: 2, insert: 'the' }, tag: 'correction' } }, + { p: 0.2, sample: { displayAs: 'them', transform: { deleteLeft: 2, insert: 'them' }, tag: 'correction' } }, + { p: 0.1, sample: { displayAs: 'tee hee', transform: { deleteLeft: 2, insert: 'tee hee' }, tag: 'correction' } }, + ]; + } else { + return []; + } + } +} diff --git a/developer/src/kmc-model/test/fixtures/example.qaa.custom/example.qaa.custom.model.ts b/developer/src/kmc-model/test/fixtures/example.qaa.custom/example.qaa.custom.model.ts new file mode 100644 index 0000000000..8f1d188f9d --- /dev/null +++ b/developer/src/kmc-model/test/fixtures/example.qaa.custom/example.qaa.custom.model.ts @@ -0,0 +1,6 @@ +const source: LexicalModelSource = { + format: 'custom-1.0', + rootClass: 'ExampleCustomModel', + sources: ['ExampleCustomModel.ts'], +}; +export default source; \ No newline at end of file diff --git a/developer/src/server/src/win32/trayicon/addon-src/package-lock.json b/developer/src/server/src/win32/trayicon/addon-src/package-lock.json index 246f1b5ffe..3b320611f1 100644 --- a/developer/src/server/src/win32/trayicon/addon-src/package-lock.json +++ b/developer/src/server/src/win32/trayicon/addon-src/package-lock.json @@ -642,9 +642,9 @@ } }, "node_modules/tar": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", - "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", + "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -1166,9 +1166,9 @@ } }, "tar": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", - "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", + "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", "requires": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", diff --git a/developer/src/test/auto/model-ts-parser/Keyman.System.Test.LexicalModelParserTest.pas b/developer/src/test/auto/model-ts-parser/Keyman.System.Test.LexicalModelParserTest.pas index 11dcd5a4a9..b26fb863f8 100644 --- a/developer/src/test/auto/model-ts-parser/Keyman.System.Test.LexicalModelParserTest.pas +++ b/developer/src/test/auto/model-ts-parser/Keyman.System.Test.LexicalModelParserTest.pas @@ -91,12 +91,17 @@ var begin lm := TLexicalModelParser.Create(m.Text); try + // TODO: LexicalModelParser does not support `rootClass` which is needed for + // custom lexical models, and the property `Wordlists` is inappropriate for + // the list of sources files. This is part of a bigger project for better + // custom model support in TIKE + // + // For now, this test excludes the `rootClass` property in order to pass lm.Comment := 'Testing'; lm.Format := lmfCustom10; lm.WordBreaker := lmwbAscii; lm.Wordlists.Clear; - lm.Wordlists.Add('foo.tsv'); - lm.Wordlists.Add('bar.tsv'); + lm.Wordlists.Add('CustomModel.ts'); Assert.AreEqual(mcustom.Text.Trim, lm.Text.Trim); // Ignoring whitespace before/after finally lm.Free; diff --git a/developer/src/test/auto/model-ts-parser/assets/custom.model.ts b/developer/src/test/auto/model-ts-parser/assets/custom.model.ts index 64e8f8e122..c22dfe0a1a 100644 --- a/developer/src/test/auto/model-ts-parser/assets/custom.model.ts +++ b/developer/src/test/auto/model-ts-parser/assets/custom.model.ts @@ -2,7 +2,7 @@ const source: LexicalModelSource = { format: 'custom-1.0', wordBreaker: 'ascii', - sources: ['foo.tsv', 'bar.tsv'] + sources: ['CustomModel.ts'] }; export default source; diff --git a/linux/debian/changelog b/linux/debian/changelog index 516340d09b..94958e3690 100644 --- a/linux/debian/changelog +++ b/linux/debian/changelog @@ -1,3 +1,9 @@ +keyman (18.0.248-1) unstable; urgency=medium + + * New upstream release. + + -- Eberhard Beilharz Thu, 12 Mar 2026 12:39:18 +0100 + keyman (18.0.247-1) unstable; urgency=medium * New upstream release. diff --git a/linux/debian/tests/control b/linux/debian/tests/control index 9163c8c213..695494d739 100644 --- a/linux/debian/tests/control +++ b/linux/debian/tests/control @@ -1,5 +1,5 @@ Tests: test-build test-gnome-cli test-ibus-cli Depends: @, build-essential, - pkg-config, + pkgconf, Architecture: amd64 arm64 armel armhf i386 loong64 mips64el mipsel ppc64el riscv64 diff --git a/linux/docs/internal/gtk-input-methods.md b/linux/docs/internal/gtk-input-methods.md new file mode 100644 index 0000000000..f340d72268 --- /dev/null +++ b/linux/docs/internal/gtk-input-methods.md @@ -0,0 +1,132 @@ +# Input Methods in GTK + +This document describes how Keyman is connected to a client app, in other words +how a keypress in the app ends up being processed by the Keyman engine. + +For text input, GTK (or rather the app) will add input method support to a widget. +How the input method gets loaded depends on the GTK version. + +IBus provides input modules for GTK 2, GTK 3, GTK 4, X11, and Wayland. +However, the Wayland one is not used with Gnome because GTK provides +its own implementation. + +Which input modules are available depends on the GTK version. Apps that +don't use the Gnome/GTK framework use different ways for input method +support. + +## GTK 4 + +```mermaid +flowchart LR + subgraph GTK + app(application) + im-module["im-ibus + (IBusIMContext)"] + app --- im-module + end + + subgraph ibus[ibus-daemon] + direction LR + IBusInputContext <--> IBusEngine + end + + subgraph keyman + ibus-engine-keyman + end + + GTK <--> ibus <--> keyman + + style app color:#FFFFFF, stroke:#00C853, fill:#00C853 +``` + +The im-module implements a [GIOExtensionPoint](https://docs.gtk.org/gio/struct.IOExtensionPoint.html) +"gtk-im-module". The type extends `GtkIMContext`. +When loading the app, GTK dynamically loads and starts the extension +specified by the environment variable `GTK_IM_MODULE` (or the default which is +probably the one with the highest priority). + +External modules are located in `/usr/lib/x86_64-linux-gnu/gtk-4.0/4.0.0/immodules` +and named `lib*.so`. + +Each module has a priority, a name and the type that implements it. + +GTK4 has built-in support for Wayland (`GtkIMContextWayland`), Broadway +(`GtkIMContextBroadway`, irrelevant for Keyman) and gtk-im-context-simple +(`GtkIMContextSimple`, irrelevant for Keyman). `GtkIMContextWayland` is +implemented as part of GTK 4, the source code can be found in +. + +The input method for ibus is implemented as an external module +(type `IBusIMContext`). Source code is in +. + +The IBus communication between `IBusIMContext`, ibus-daemon and the ibus +engine (aka Keyman) happens with DBus messages on a separate IBus DBus +instance. + +## GTK 2/GTK 3 + +With older GTK versions basically the same components are involved, +although a different mechanism to discover and load the +im-modules is used. + +GTK caches the available modules in a module database located in +`/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules.cache` or whereever +the `GTK_IM_MODULE_FILE` environment variable points. This database is +read on application startup. + +For each module the database contains an id, the name, the path, i18n domain(?) +and default locales. + +GTK then determines what input module to load based on the `GTK_IM_MODULE` +environment variable (which can contain more than one module separated by +colons) or the `XSETTINGS` `gtk-im-module` property. It then checks that +the currently running display type is compatible with the module, and that +the current locale matches the locales supported by the module. An exact match +(`en_US` vs `en_US`) gets 4 points, a match of the language (`en_US` vs `en`) +gets 3 points, a match with a different region (`en_US` vs `en_UK`) 2 points, +and a wildcard (`en_US` vs `*`) 1 point. + +Each input module implements a subclass of `GTKIMContext` plus the 4 required +entry points: + +- `im_module_init()` - Initialize module +- `im_module_list()` - Describe available contexts +- `im_module_create()` - Create context instance +- `im_module_exit()` - Cleanup on unload + +GTK uses `GModule` to dynamically load the module's `.so` file and then calls +`im_module_init()` on the module, followed by `im_module_create()` to instantiate +the actual `GtkIMContext` subclass. + +If no module matches or loading fails, GTK falls back to `GtkIMContextSimple`. + +GTK3 provides support for several input methods, more than with GTK4. Those +can be found in . +Among the built-in modules are `im-wayland` (for Wayland), `im-xim` (for X11), +`im-thai` (for Thai), and `im-ime` (for Windows). + +The input method for ibus is implemented as an external module +(type `IBusIMContext`). Source code is in +. + +All modules are located in `/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules` +and named `*.so`, e.g. `im-ibus.so`. + +After installing a new module the database needs to be updated with +`sudo /usr/lib/x86_64-linux-gnu/libgtk-3-0t64/gtk-query-immodules-3.0 --update-cache`. + +## Tips + +- GTK has a built-in + [inspection/debugging tool](https://developer.gnome.org/documentation/tools/inspector.html) + which can be opened with Ctrl+Shift+I, or + Ctrl+Shift+D, or by setting the + environment variable `GTK_DEBUG=interactive`. +- Available GTK3 IM modules can be listed with + `/usr/lib/x86_64-linux-gnu/libgtk-3-0t64/gtk-query-immodules-3.0` or by + looking at `/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules.cache`. + +## Links + +- [GTK4 Input Handling](https://docs.gtk.org/gtk4/input-handling.html) \ No newline at end of file diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index dd9a8a3cee..9cf29e5b89 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -8,6 +8,7 @@ #import "KMInputMethodEventHandler.h" #import #import /* For kVK_ constants. */ +#import #import "KeySender.h" #import "TextApiCompliance.h" #import "KMSettingsRepository.h" @@ -370,7 +371,7 @@ CGEventSourceRef _sourceForGeneratedEvent = nil; contextString = attributedString.string; //only uncomment for testing as we do not want to write context in logs - //os_log_debug([KMLogs testLog], " length: %lu result: %{public}@", contextString.length, contextString); + //os_log_debug([KMLogs keyTraceLog], " length: %lu result: %{public}@", contextString.length, contextString); } } } @@ -405,18 +406,7 @@ CGEventSourceRef _sourceForGeneratedEvent = nil; [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; [self insertAndReplaceTextForOutput:output client:client]; } else if (output.isDeleteOnlyScenario) { - if ((event.keyCode == kVK_Delete) && output.codePointsToDeleteBeforeInsert == 1) { - // let the delete pass through in the original event rather than sending a new delete - NSString *message = @"applyOutputToTextInputClient, delete only scenario with passthrough"; - os_log_debug([KMLogs keyTraceLog], "%@", message); - [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; - handledEvent = NO; - } else { - NSString *message = @"applyOutputToTextInputClient, delete only scenario"; - os_log_debug([KMLogs keyTraceLog], "%@", message); - [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; - [self sendEvents:event forOutput:output]; - } + handledEvent = [self handleDeleteOnlyScenario:output keyDownEvent:event client:client]; } else if (output.isDeleteAndInsertScenario) { // TODO: fix issue #10246 /* @@ -511,6 +501,220 @@ CGEventSourceRef _sourceForGeneratedEvent = nil; } } +/** + * Handles deleting without an associated insert in one of three methods: + * 1. delete via replace: do the delete by replacing two (or more) characters with one. + * 2. backspace passthrough : if the original keydown event was a backspace, pass it through unhandled + * 3. generate event: generate keydown backspace events as necessary + */ +-(BOOL)handleDeleteOnlyScenario:(CoreKeyOutput*)output keyDownEvent:(nonnull NSEvent *)event client:(id) client { + + // attempt to delete by replacing -- for compliant apps only + if ([self handleDeleteWithReplacement:output keyDownEvent:event client:client]) { + return YES; + } + + // pass through if this was a backspace keydown event + if (event.keyCode == kVK_Delete && output.codePointsToDeleteBeforeInsert == 1) { + // let the delete pass through in the original event rather than sending a new delete + NSString *message = @"handleDeleteOnlyForOutput, delete only scenario with passthrough"; + os_log_debug([KMLogs keyTraceLog], "%@", message); + [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; + + // instruct system to handle the event + return NO; + } + else { + // otherwise generate a backspace + NSString *message = @"handleDeleteOnlyForOutput, send backspace event"; + os_log_debug([KMLogs keyTraceLog], "%@", message); + [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; + [self sendEvents:event forOutput:output]; + + return YES; + } +} + +/** + * For compliant apps only. + * + * This an attempt to make sure that deletion removes only the expected codepoints. + * When handling a transform which only deletes a character, or when allowing a + * backspace to pass through, the OS or application may not use the same rules + * around deletion as Keyman -- especially when deleting clusters such as letter + + * combining diacritic (e.g. `U+0062 U+0301`), where some applications may delete + * both together as they represent a single 'grapheme cluster'. + * + * (Note, the question of whether it is appropriate for backspace to delete a + * cluster rather than a codepoint from an end-user perspective is not relevant + * here, because what is important is that we match the rules that the keyboard has + * provided, which means we need a method of deleting a precise number of + * codepoints. The keyboard author can and should include rules for cluster + * deletion that meet end-user expectations.) + * + * The `insertText` API takes two parameters: a string to insert, and a range to + * replace with that string. However, we cannot simply pass through a zero-length + * insertion string along with the range to delete, because the `insertText` API + * treats this as an invalid call and ignores it. + * + * Instead, we can delete the desired number of codepoints only by using the + * `insertText` API to replace e.g. two codepoints with one. + * + * This method only works for compliant apps because non-compliant apps do not + * support the `insertText` API. + * + * Ref: https://developer.apple.com/documentation/appkit/nstextinputclient/inserttext(_:replacementrange:) + */ +-(BOOL)handleDeleteWithReplacement:(CoreKeyOutput*)output keyDownEvent:(nonnull NSEvent *)event client:(id) client { + BOOL handledEvent = NO; + NSString *context = [self readContext:event forClient:client]; + + // guard: only for compliant apps with sufficient context + if (!(self.apiCompliance.canReplaceText) || ([context length] <= output.textToDelete.length)) { + os_log_debug([KMLogs keyTraceLog], "cannot replace text, non-compliant or insufficient context"); + return NO; // return without deleting/replacing + } + + // guard: the logic of this method depends on locating textToDelete in the context + if (![self stringToDeleteMatchesContextSuffix:output.textToDelete context:context]) { + os_log_debug([KMLogs keyTraceLog], "cannot replace text, textToDelete not found at end of context"); + return NO; // return without deleting/replacing + } + + NSUInteger deletionTargetLength = output.textToDelete.length; + NSUInteger deletionTargetLocation = context.length-deletionTargetLength; + NSUInteger precedingCharacterLocation = deletionTargetLocation - 1; + + // if the preceding character is the trailing half of a surrogate pair + // then delete by replacing with the entire surrogate pair + if ([self precededBySurrogatePair:precedingCharacterLocation context:context]) { + handledEvent = [self deleteByReplacingWithPrecedingSurrogate:precedingCharacterLocation deleteLength:deletionTargetLength context:context client:client]; + } else { + // otherwise replace with only the preceding character + handledEvent = [self deleteByReplacingWithPrecedingCharacter:precedingCharacterLocation deleteLength:deletionTargetLength context:context client:client]; + } + + return handledEvent; +} + +/** + * Check whether the string to be deleted is found at the tail end of the current context. + */ +-(BOOL) stringToDeleteMatchesContextSuffix:(NSString*)textToDelete context:(NSString*) context { + BOOL doesMatch = NO; + + // get length of string to delete and compare to end of context + NSUInteger deleteLength = textToDelete.length; + NSUInteger locationOfDeletionTarget = context.length-deleteLength; + NSUInteger locationOfPrecedingCharacter = locationOfDeletionTarget - 1; + NSString *contextSuffix = [context substringFromIndex:context.length-deleteLength]; + + os_log_debug([KMLogs keyTraceLog], "stringToDeleteMatchesSuffix, textToDelete: '%{public}@', contextSuffix: '%{public}@', locationOfDeletionTarget: %u, locationOfprecedingCharacter: %u", textToDelete, contextSuffix, (int)locationOfDeletionTarget, (int)locationOfPrecedingCharacter); + + doesMatch = [textToDelete isEqualToString:contextSuffix]; + os_log_debug([KMLogs keyTraceLog], "stringToDeleteMatchesSuffix: %{public}@", doesMatch?@"YES":@"NO"); + return doesMatch; +} + +/** + * Check whether the preceding character, which is to be used for the replacement, + * is part of a surrogate pair that is distinct from the character being deleted. + */ +-(BOOL) precededBySurrogatePair: (NSUInteger)precedingLocation context:(NSString*) context { + BOOL precedingCharacterIsLowSurrogate = false; + unichar precedingCharacter = [context characterAtIndex:precedingLocation]; + + if (CFStringIsSurrogateHighCharacter(precedingCharacter)) { + // preceding character is high character -- unexpected from Keyman Core + // write to log and return false + precedingCharacterIsLowSurrogate = false; + NSString *message = [NSString stringWithFormat:@"Unexpected high surrogate found for preceding character at %ld", (long)precedingCharacter]; + os_log_debug([KMLogs keyTraceLog], "%{public}@", message); + [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; + } else if (CFStringIsSurrogateLowCharacter(precedingCharacter)) { + // preceding character is low surrogate + precedingCharacterIsLowSurrogate = true; + } + + return precedingCharacterIsLowSurrogate; +} + +/** + * Replace both the text to delete and the character preceding it solely with the character that precedes it. + * Returns YES if executing the replace/delete and NO otherwise. + */ +-(BOOL) deleteByReplacingWithPrecedingCharacter:(NSUInteger)precedingCharacterLocation deleteLength:(NSUInteger)deleteLength context:(NSString*) context client:(id) client { + + os_log_debug([KMLogs keyTraceLog], "deleteByReplacingWithPrecedingCharacter"); + // get the preceding character + NSRange precedingCharacterRange = NSMakeRange(precedingCharacterLocation, 1); + NSString *replacementString = [context substringWithRange:precedingCharacterRange]; + + // guard: if preceding character is a control character, return NO + if ([self containsControlCharacter:replacementString]) { + NSString *message = @"replacementString contains control characters, cannot delete with replace"; + os_log_debug([KMLogs keyTraceLog], "%@", message); + [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; + return NO; + } + + // perform the replacement + NSUInteger replacementLength = [replacementString length] + deleteLength; + NSRange replacementRange = NSMakeRange(precedingCharacterLocation, replacementLength); + os_log_debug([KMLogs keyTraceLog], "replacementRange: %{public}@", NSStringFromRange(replacementRange)); + [client insertText:replacementString replacementRange:replacementRange]; + + return YES; +} + +/** + * Replace both the text to delete and the surrogate pair preceding it with the surrogate pair preceding it. + * Returns YES if executing the replace/delete and NO otherwise. + */ +-(BOOL) deleteByReplacingWithPrecedingSurrogate:(NSUInteger)precedingCharacterLocation deleteLength:(NSUInteger)deleteLength context:(NSString*) context client:(id) client { + + os_log_debug([KMLogs keyTraceLog], "deleteByReplacingWithPrecedingSurrogate"); + + // guard: return NO if there is no character before the precedingCharacterLocation + if (precedingCharacterLocation <= 0) { + NSString *message = @"no characters exist before precedingCharacterLocation, so it cannot be a surrogate pair"; + os_log_debug([KMLogs keyTraceLog], "%@", message); + return NO; + } + + // get the preceding character + NSRange precedingCharacterRange = NSMakeRange(precedingCharacterLocation - 1, 2); + NSString *replacementString = [context substringWithRange:precedingCharacterRange]; + + unichar highCharacter = [replacementString characterAtIndex:0]; + unichar lowCharacter = [replacementString characterAtIndex:1]; + + // verify that preceding characters comprise a surrogate pair + if ((CFStringIsSurrogateHighCharacter(highCharacter)) && (CFStringIsSurrogateLowCharacter(lowCharacter))) { + // found preceding surrogate as expected + } else { + NSString *message = [NSString stringWithFormat:@"Preceding characters of string do not comprise a surrogate pair: 0x%02x, 0x%02x", (unsigned int)highCharacter, (unsigned int)lowCharacter]; + os_log_debug([KMLogs keyTraceLog], "%@", message); + [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; + return NO; + } + + // perform the replacement + NSUInteger replacementLength = [replacementString length] + deleteLength; + NSRange replacementRange = NSMakeRange(precedingCharacterRange.location, replacementLength); + os_log_debug([KMLogs keyTraceLog], "replacementRange: %{public}@", NSStringFromRange(replacementRange)); + [client insertText:replacementString replacementRange:replacementRange]; + + return YES; +} + +-(BOOL) containsControlCharacter:(NSString*)text { + NSCharacterSet *controlSet = [NSCharacterSet controlCharacterSet]; + NSRange range = [text rangeOfCharacterFromSet:controlSet]; + + return (range.location != NSNotFound); +} + /** * Calculates the range where text will be inserted and replace existing text. * Returning {NSNotFound, NSNotFound} for range signifies to insert at current location without replacement. diff --git a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h index 1f5b55f17f..40c516a8db 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN -(void) checkComplianceAfterInsert:(NSString *)insertedText deleted:(NSString *)deletedText; -(BOOL)isComplianceUncertain; -(BOOL)canReadText; +-(BOOL)canReplaceText; -(BOOL)mustBackspaceUsingEvents; @end diff --git a/resources/build/pr-build-status/pr-build-status.prefix.yml b/resources/build/pr-build-status/pr-build-status.prefix.yml index cbeba112a1..d82aa9cb77 100644 --- a/resources/build/pr-build-status/pr-build-status.prefix.yml +++ b/resources/build/pr-build-status/pr-build-status.prefix.yml @@ -32,6 +32,6 @@ jobs: steps: - name: Check PR build status id: run_pr_build_status_script - uses: actions/github-script@v7 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | diff --git a/resources/teamcity/includes/tc-helpers.inc.sh b/resources/teamcity/includes/tc-helpers.inc.sh index b4c62826e1..6f704ef1f4 100644 --- a/resources/teamcity/includes/tc-helpers.inc.sh +++ b/resources/teamcity/includes/tc-helpers.inc.sh @@ -65,8 +65,26 @@ _tc_rsync() { else local RSYNC=rsync if builder_is_macos; then + # We need to look for a newer version of rsync because the version bundled + # with macos does not work correctly; we assume that this is installed + # with Homebrew. On Intel, this is found in /usr/local/bin, and on M1, it + # is found in /opt/homebrew/bin. + RSYNC=/usr/local/bin/rsync - [[ -f /opt/homebrew/bin/rsync ]] && RSYNC=/opt/homebrew/bin/rsync + [[ -x /opt/homebrew/bin/rsync ]] && RSYNC=/opt/homebrew/bin/rsync + + # On build agents, we unlink rsync from homebrew, because otherwise xcode + # builds which use rsync internally fail, so we need to specify the full + # path to rsync. Generally, rsync is not needed on developer machines as + # this is only used for release builds from the build agents. #15764 + if [[ ! -x "${RSYNC}" ]]; then + # Try and find the rsync binary with `brew list`. It should be something + # like `/opt/homebrew/Cellar/rsync/3.4.1/bin/rsync` + RSYNC="$(brew list rsync | grep /bin/rsync\$)" + if [[ ! -x "${RSYNC}" ]]; then + builder_die "Could not find Homebrew-installed rsync anywhere" + fi + fi fi ${RSYNC} "${rsync_args[@]}" diff --git a/resources/teamcity/includes/tc-mac.inc.sh b/resources/teamcity/includes/tc-mac.inc.sh index 0e9c18013c..a138789cf5 100644 --- a/resources/teamcity/includes/tc-mac.inc.sh +++ b/resources/teamcity/includes/tc-mac.inc.sh @@ -12,9 +12,13 @@ ba_mac_unlock_keychain() { } ba_mac_clean_xcode_derived_data() { - builder_echo start "clean" "Cleaning XCode DerivedData mess" + builder_echo start "clean" "Cleaning XCode DerivedData and Carthage cache mess" rm -rf "${HOME}/Library/Developer/Xcode/DerivedData" - builder_echo end "clean" success "Finished cleaning XCode DerivedData mess" + + # https://stackoverflow.com/a/45504898/1836776 + rm -rf "${HOME}/Library/Caches/org.carthage.CarthageKit" + + builder_echo end "clean" success "Finished cleaning XCode DerivedData and Carthage cache mess" } ba_mac_unmount_volumes_keyman() {