diff --git a/developer/19.0/reference/messages/developer-utils.developerutilsmessages.md b/developer/19.0/reference/messages/developer-utils.developerutilsmessages.md
index 3dd717e43..ffa4373d6 100644
--- a/developer/19.0/reference/messages/developer-utils.developerutilsmessages.md
+++ b/developer/19.0/reference/messages/developer-utils.developerutilsmessages.md
@@ -16,3 +16,4 @@ title: Compiler Messages Reference for @keymanapp/developer-utils
[KM0100A](km0100a) | `ERROR_InvalidProjectFile` | Project file is not valid: <param>
[KM0100B](km0100b) | `ERROR_UnsupportedProjectVersion` | Project version <param> is not supported by this version of Keyman Developer\.
[KM0100C](km0100c) | `ERROR_ProjectFileCouldNotBeRead` | Project file could not be read
+[KM0100D](km0100d) | `ERROR_NotAPackageFile` | Package source file is not a valid \.kps file because it is missing the <Package> root element\.
diff --git a/developer/19.0/reference/messages/km0100d.md b/developer/19.0/reference/messages/km0100d.md
new file mode 100644
index 000000000..e438ec067
--- /dev/null
+++ b/developer/19.0/reference/messages/km0100d.md
@@ -0,0 +1,11 @@
+---
+title: KM0100D: ERROR_NotAPackageFile
+---
+
+| | |
+|------------|---------- |
+| Message | Package source file is not a valid \.kps file because it is missing the <Package> root element\. |
+| Module | [developer-utils.DeveloperUtilsMessages](developer-utils.developerutilsmessages) |
+| Identifier | `ERROR_NotAPackageFile` |
+
+
diff --git a/developer/core/19.0/index.md b/developer/core/19.0/index.md
index 94bb51765..427e6f1de 100644
--- a/developer/core/19.0/index.md
+++ b/developer/core/19.0/index.md
@@ -19,6 +19,7 @@ This is an internal API intended for use only within Keyman Engine.
* [Options](options)
* [Processor](processor)
* [State and Actions](state)
+* [Key Handling](keyhandling)
* [JSON introspection Schema](json-schema)
* [Building Keyman Core](building)
@@ -122,4 +123,4 @@ Caps Lock.
[km_core_event_flags]: processor#km_core_event_flags "km_core_event_flags enum"
[km_core_process_event]: processor#km_core_process_event "km_core_process_event function"
[km_core_event]: processor#km_core_event "km_core_event function"
-[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
\ No newline at end of file
+[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
diff --git a/developer/core/19.0/json-schema.md b/developer/core/19.0/json-schema.md
index 756d5c496..4fca89e67 100644
--- a/developer/core/19.0/json-schema.md
+++ b/developer/core/19.0/json-schema.md
@@ -4,10 +4,10 @@ title: JSON Introspection Schema
The [`km_core_state_to_json()`](state#km_core_state_to_json) call
generates a JSON document describing the internal state of the keyboard
-processor, this is the schema describing that document.
+processor. This is the schema describing that document.
**WARNING**: The structure and format of the JSON document is independently
-versioned is not considered part of C API. It is intended solely for use in
+versioned and is not considered part of the C API. It is intended solely for use in
diagnostics or by development and debugging tools which may need to be aware of
keyboard processor engine implementation details.
@@ -74,4 +74,4 @@ keyboard processor engine implementation details.
"context": { "$ref": "#/definitions/context" }
}
}
-```
\ No newline at end of file
+```
diff --git a/developer/core/19.0/keyhandling.md b/developer/core/19.0/keyhandling.md
new file mode 100644
index 000000000..6dcc3177b
--- /dev/null
+++ b/developer/core/19.0/keyhandling.md
@@ -0,0 +1,42 @@
+# 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.
+
+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.
+
+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.
+
+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 |
+
+1: context available
+2: without or with empty context
diff --git a/developer/core/19.0/options.md b/developer/core/19.0/options.md
index f51528eaf..c5539d7ae 100644
--- a/developer/core/19.0/options.md
+++ b/developer/core/19.0/options.md
@@ -3,7 +3,7 @@ title: Options - Keyman Core API
---
A state’s default options are set from the keyboard at creation time and the
-environment. The Platform layer is then is expected to apply any persisted
+environment. The Platform layer is then expected to apply any persisted
options it is maintaining. Options are passed into and out of API functions as
simple C arrays of [km_core_option_item] terminated with a `KM_CORE_OPTIONS_END`
sentinel value. A state's options are exposed and manipulatable via the
@@ -281,4 +281,4 @@ km_core_state_options_to_json(km_core_state const *state,
[km_core_event_flags]: processor#km_core_event_flags "km_core_event_flags enum"
[km_core_process_event]: processor#km_core_process_event "km_core_process_event function"
[km_core_event]: processor#km_core_event "km_core_event function"
-[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
\ No newline at end of file
+[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
diff --git a/developer/core/19.0/processor.md b/developer/core/19.0/processor.md
index c72d743bb..e8a8f7c0f 100644
--- a/developer/core/19.0/processor.md
+++ b/developer/core/19.0/processor.md
@@ -15,8 +15,8 @@ enum km_core_event_flags {
KM_CORE_EVENT_FLAG_DEFAULT = 0,
KM_CORE_EVENT_FLAG_TOUCH = 1,
};
-
```
+
## Values
`KM_CORE_EVENT_FLAG_DEFAULT`
@@ -195,4 +195,4 @@ enum km_core_event_code {
[km_core_event_flags]: processor#km_core_event_flags "km_core_event_flags enum"
[km_core_process_event]: processor#km_core_process_event "km_core_process_event function"
[km_core_event]: processor#km_core_event "km_core_event function"
-[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
\ No newline at end of file
+[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
diff --git a/developer/core/19.0/state.md b/developer/core/19.0/state.md
index 0292d9f8a..32d3dc9b3 100644
--- a/developer/core/19.0/state.md
+++ b/developer/core/19.0/state.md
@@ -15,7 +15,8 @@ owned by the state object.
## Description
-Describes the
+Describes a change to the hardware caps lock indicator state requested by
+Keyman Core to the Platform layer.
## Specification
```c
@@ -50,6 +51,7 @@ This API replaces the Action items APIs, which are now deprecated and will be
removed in the future.
## Specification
+
```c
typedef struct {
unsigned int code_points_to_delete;
@@ -60,8 +62,8 @@ typedef struct {
km_core_caps_state new_caps_lock_state;
const km_core_usv* deleted_context;
} km_core_actions;
-
```
+
## Members
`code_points_to_delete`
@@ -78,15 +80,17 @@ typedef struct {
`emit_keystroke`
: Emit the (unmodified) input keystroke to the application, 0 = no, 1 = yes.
+ On most platforms this signals whether the processor handled the event
+ (0) or not (1). See also [key handling](keyhandling).
`new_caps_lock_state`
: -1=unchanged, 0=off, 1=on
`deleted_context`
: Reference copy of actual UTF32 codepoints deleted from end of context
- (closest to caret) exactly code_points_to_delete in length (plus null
+ (closest to caret) exactly `code_points_to_delete` in length (plus null
terminator). Used to determine encoding conversion differences when
- deleting; only set when using [km_core_state_get_actions], otherwise nullptr.
+ deleting; only set when using [km_core_state_get_actions], otherwise `nullptr`.
-------------------------------------------------------------------------------
@@ -282,4 +286,4 @@ An opaque pointer to a state object.
[km_core_event_flags]: processor#km_core_event_flags "km_core_event_flags enum"
[km_core_process_event]: processor#km_core_process_event "km_core_process_event function"
[km_core_event]: processor#km_core_event "km_core_event function"
-[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"
\ No newline at end of file
+[km_core_event_code]: processor#km_core_event_code "km_core_event_code enum"