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.
*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':
-
-
-
-Or if in 'landscape' view, key heights are too small:
-
-
-
-The situation is improved markedly if we limit the number of keys per row to ten
-and have no more than four key rows:
-
-
-
-and, in landscape view:
-
-
-
-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:
-
-
-
-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).
-
-
-
-## 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:
-
-
-
-
-
Identifier
-
Meaning
-
-
-
-
-
`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.
-
-
-
-
-
Identifier
-
Meaning
-
-
-
-
-
`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 String
-
Key Cap
-
Key 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:
-
-
-
-### 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 Type
-
Value
-
Meaning
-
-
-
-
-
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:
-
-
-
-
-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:
-
-
-
-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:
-
-
-
-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:
-
-
-
-## 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” .
-
-
-
-## 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”.
-
-
-
-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.
-
-
-
-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.”
-
-
-
-Keyman developer asks me to choose one of three templates for the mobile
-layout.
-
-
-
-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.
-
-
-
-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).
-
-
-
-## 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.
-
-
-
-I click that, and Keyman Developer adds a new key below the keyboard
-layout.
-
-
-
-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.
-
-
-
-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).
-
-
-
-## 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:
-
-
-
-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.
-
-
-
-[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`.
-
-
-
-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:
-
-
-
-(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”
-
-
-
-## 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".
-
-
-
-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.
-
-
-
-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:
-
-
-
-I’ll do the similar step to add two characters as a longpress popup for
-“b”
-
-
-
-And two characters as a longpress popup for “n”. (Tip, to search for ŋ
-in the character map, type “eng”).
-
-
-
-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.
-
-
-
-## 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:
-
-
-
-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:
-
-
-
-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:
-; 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 bc 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 ac 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 cd (because c by itself has no rule), and bd.
-
-## 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.
-
-
-
-## 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".
-
-
-
-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.
-
-
-
-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.
-
-
-
-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
-
-
-
-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
-
-
\ 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.
-
-
-
-Safari will display an option to open the KMP file with Keyman
-
-
-
-## 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
-
-
-
-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!
-
-
-
-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
-
-
+(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:
-
--  includes fonts
--  includes documentation
--  includes on screen keyboards
--  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.
-
-
-
-- 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.
-
-
-
-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.
-
-
-
-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.
-
-
-
-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.
-
-
-
-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  is a faded version of the Keyman icon .
+
+
+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)
+
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)
+
+[← 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.
+
+
+
+- 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.
+
+
+
+
+
+- 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).
+
+
+
+- Note that information about this key is placed to the right.
+
+
+
+- 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.
+
+
+
+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.)
+
+
+
+- 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`.
+
+
+
+- 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:
+
+
+
+- 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.
+
+
+
+- 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.
+
+
+
+- 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:
+
+
+
+- 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.
+
+
+
+- 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.
+
+
+
+- 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)
+
+
Shift
+
+
Right Alt (unshifted)
+
+```
+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`.
+
+
+
+- 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.
+
+
+
+- Select the `Test Lexical Model` button, then the `Open in browser` button. You should have a new browser tab that looks like:
+
+
+
+- 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.
+
+
+
+- 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.
+
+
+
+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:
+
+
+
+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.
+
+
+
+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)!
+
+
+
+- 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:
+
+
+
+- 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:
+
+
+
+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:
+
+
+
+- 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:
+
+
+
+
+[← 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)
+