-
-
Notifications
You must be signed in to change notification settings - Fork 41
docs(windows): describe windows compliant app implementation with sequence diagram #2326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b727871
6993630
b2e1d9e
842d4bc
1f55e0a
d961009
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| sequenceDiagram | ||
| autonumber | ||
| participant User as User | ||
| participant OS as Windows OS | ||
| participant TSF as TSF Manager | ||
| participant Keyman as Keyman TIP | ||
| participant App as Application (Compliant) | ||
|
|
||
| User->>OS: Press key (e.g. 'D') | ||
| OS->>TSF: Deliver key event | ||
| TSF->>Keyman: Call OnKeyDown(ITfContext) | ||
|
|
||
| Note right of Keyman: Keyman create TIPEditSession & requests context | ||
| Keyman->>TSF: ITfContext.GetStatus() | ||
| Keyman->>TSF: ITfContext.GetSelection() | ||
| TSF->>App: Request current selection | ||
| App-->>TSF: Return caret/selection | ||
| TSF-->>Keyman: Return GetSelection | ||
|
|
||
|
|
||
| Note right of Keyman: Keyman applies keyboard rules and computes output | ||
|
|
||
| Keyman->>TSF: ITfContext.SetText() | ||
| TSF->>App: Delete or replace text in range | ||
|
|
||
| App-->>User: Display “∆” in document | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,4 +223,61 @@ on the Keyman system service which emits a fake key event. That way it is possib | |
|
|
||
| ## Compliance on Windows | ||
|
|
||
| TODO | ||
| Compliance on Windows | ||
|
|
||
| On Windows, Keyman integrates with applications primarily through the Text Services Framework (TSF). Keyman implements a Text Input Processor (TIP) that communicates with the TSF manager and the target application. | ||
rc-swag marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| When the user types, the TSF manager passes key events and text context to Keyman through the ITfContext interface, which provides access to the current edit context within the application. Keyman relies on this interface to retrieve context, determine the current selection, and insert or replace text. | ||
| For ITfContext details see [Learn Microsoft](https://learn.microsoft.com/en-us/windows/win32/api/msctf/nn-msctf-itfcontext). | ||
rc-swag marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Relevant for Keyman are the following API functions: | ||
|
|
||
| **`GetStatus()`** — Retrieves the current status of the text context. Keyman uses this to check for the TF_SS_TRANSITORY flag, which indicates temporary or non-standard contexts that may not behave consistently. | ||
|
|
||
| **`GetSelection()`** — Retrieves the current text selection or caret position. | ||
|
|
||
| **`SetSelection()`** — Updates the current selection or caret position after Keyman inserts or replaces text. | ||
|
|
||
| **`GetText()`** — Retrieves text from a specified range around the caret, giving Keyman the context needed to process complex keyboard rules. | ||
|
|
||
| **`SetText()`** — Replaces text in a specific range within the context. | ||
|
||
|
|
||
| Applications can restrict how much surrounding text can be read; Keyman limits its requests to 64 characters of context. | ||
|
|
||
| <img src="./assets/kb0118/windows-compliant-app-sequence.png" width="75%" alt="compliant sequence on Windows"/> | ||
|
|
||
| The sequence diagram is for a rule that replaces "D" with "∆". | ||
|
|
||
| Keyman determines whether an application is compliant by inspecting the status returned by `ITfContext::GetStatus()`. | ||
|
|
||
| - **Compliant applications** provide a stable, non-transitory context and correctly implement the TSF APIs needed to retrieve context and modify text. | ||
| - **Non-compliant applications** may expose only a transitory context or fail to return reliable selection or text data. | ||
|
||
|
|
||
| If the `TF_SS_TRANSITORY` flag is present or context cannot not be read as expected, Keyman treats the application as non-compliant and falls back to legacy behavior, maintaining its own internal context buffer and simulating text operations where possible. | ||
rc-swag marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Non-compliance on Windows | ||
|
|
||
| When a non-compliant application is detected, Keyman falls back to **legacy behavior**. | ||
|
|
||
| With non-compliant applications, Keyman maintains an **internal context buffer** that records the characters it has recently output. This buffered context is used to apply keyboard rules that depend on previously typed characters. | ||
|
|
||
|
|
||
| ### Limitations of legacy behavior | ||
|
|
||
| The internal context buffer remains valid only while Keyman has exclusive knowledge of text changes. The buffer becomes invalid if the user performs actions such as: | ||
|
|
||
| - Moving the caret using the mouse or keyboard | ||
| - Changing the selection | ||
| - Using shortcut keys or menu commands to edit text | ||
| - Switching to another application or document | ||
|
|
||
| When such an action occurs, Keyman discards its internal context and assumes an empty context. If this happens in the middle of typing a multi-character sequence, the sequence may not be recognized correctly and may need to be retyped. | ||
|
||
|
|
||
| ### Simulating text operations | ||
|
|
||
| Because TSF APIs cannot be relied upon in non-compliant applications, Keyman may simulate text operations by generating keyboard events: | ||
|
|
||
| - **Backspace key events** are used to delete previously typed characters | ||
| - **Synthetic key events** may be used to insert characters | ||
|
|
||
| These simulated events are asynchronous and are processed by the application in sequence. As a result, text deletion and insertion may not always behave exactly as intended, particularly when dealing with composed characters or surrogate pairs. | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does
SetTextallow to specify whether to insert the text or replace the selection, or do we have to update the selection first?