diff --git a/CLAUDE.md b/CLAUDE.md index 4af1904..2ab2924 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -129,6 +129,43 @@ left off" landing on the last real visit and never on the start screen, and to a install made before the mode existed still opening where it always did. Needs only the .NET 6 SDK under `~/.dotnet-local`. +### The keyboard harness + +Any change to `KeyboardLayouts` or `KeyboardEntry` — the grids the on-screen +keyboard shows, the move between rows, and the text with its caret — is exercised +off-device first: + +```sh +tools/keyboard/run.sh +``` + +It compiles the shipping files against a stub store and log and holds them to the +shape both keyboards build their cells for, to a move between rows landing on the +key underneath rather than the key with the same index (issue #92: the rows are +centred and the action row is wider, so the same index is two keys away), and to +the caret typing, deleting and stopping where it should. Both files are in +`src/common`, so a mistake is in all six packages, and the ewk ones cannot be +tried before somebody installs them. Needs only the .NET 6 SDK under +`~/.dotnet-local`. + +### The pointer harness + +Any change to the pointer half of `PageScript` — `install`, `hide`, `show`, `move` +and the `visibilitychange` hook — is exercised against desktop chromium first: + +```sh +tools/pointer/run.sh +``` + +It lifts the shipping script out of the `.cs` and holds it to one contract: install +puts the arrow in the DOM, hide and show decide whether it is seen, and nothing the +page does on its own (a visibilitychange, a re-install, a move, a single-page +navigation wiping the overlay, the whole script run again) changes that decision. +Issue #91 was that contract not existing: the app hid the arrow to draw its own +pointer, the page brought it back on the first visibilitychange, and the reporter +saw two pointers one on top of the other. From a TV that is indistinguishable +from the app having drawn two. + ### The site-rules harness Any change to `SiteRules` — the per-site images/identity rules, and the "which diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 6c76158..db065fd 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -1307,6 +1307,35 @@ to break them is the whole reason the source is split this way. They get the coalescing, which is the half that is safe everywhere, and key `2` was already there for the rest. +### The page's arrow has to remember it was told to go away + +Issue #91, from the same set once NUI was drawing the pointer itself: "sometimes +when load app where it shows two cursor one on top of other". Two pointers, one +exactly under the other, is the app's dot and the page's arrow both showing at +the same viewport fraction — and the app had asked the page to hide the arrow, +so the question was who put it back. + +The page script did, on its own. Its `visibilitychange` listener re-runs +`install()`, which is there because a single-page navigation wipes the overlay +out of the DOM; `install()` set the arrow `display:block` unconditionally, and +nothing in the script remembered that `hide()` had been called. `visibilitychange` +fires on a great deal more than a navigation — the app coming to the front at +launch, the set's own menus going over it, the screen blanking — which is the +"sometimes" and the "when load app". The ElmSharp builds had the same fault +behind key `2` and nobody had used it long enough to see it. + +So `hide()` is remembered (`st.hidden`), `install()` honours it, and `show()` is +the only call that clears it. Both cursor classes ask for the arrow by name when +they switch to the page-drawn pointer, rather than relying on a re-install to +bring it back — which on the ElmSharp build it never reliably did: toggling to +the page's arrow after the native one had hidden it left it hidden until the next +page load. On NUI, `Reinstall` also sends the install and the hide in **one** +evaluation, so there is no ordering between them to be wrong. The shape of the +page script's contract is now: install puts the arrow in the DOM, hide and show +decide whether it is seen, and the two are independent. `tools/pointer/run.sh` +runs the shipping script in desktop chromium and fails on the old file at the +third check. + ### The one thing a script cannot click: another origin's frame `elementFromPoint` stops at an `