Fixes#6364.
Removes `&layerChanged` and adds `&newLayer` and `&oldLayer` system
stores with the additional nuances around values as described in #6364.
The Caps Lock change I made in the previous commit broke
desktop Caps Lock handling. The fix was a little more
convoluted. Turns out that _UpdateVKShift is also pretty
crufty. I simplified it, removing dead code.
Selecting the new Caps Lock `caps` layer was not correctly setting the
layer state in the key event to `caps`, which caused Caps Lock rules
to fail to match.
Relates to #5853 and others.
Selection management was not working properly with the various
OutputTargets:
1. When there is a non-empty selection, rules have no context -- it's
like new text.
2. Backspace over a selection deletes just the selection.
3. Typing a character replaces the selection, of course, and collapses
the caret to the end of the new text.
4. `hasSelection` is a very strange name for `OutputTarget` descendants.
It doesn't mean "has an active selection" but rather, kinda means
"supports selection internally".
5. Added `isSelectionEmpty` which is used for some of the new selection
rules above.
Note that the `touchAlias` OutputTarget class does not currently support
selection. I hope we can deprecate `touchAlias` with the use of
`inputMode` (#3030) in the future, rather than adding support for
selection.
Relates to #5853.
Two things happened here:
1. Construction of Mocks made an assumption that the selection should
always be deleted (outputTarget.ts:363). However, for NewContext and
PostKeystroke processes, we don't want to change anything.
2. Even if nothing is changed, the transcription would emit what is
in theory a no-op ruleTransform (insert="", deleteLeft=0,
deleteRight=0). But apps would treat this as deleting the selection.
This fix goes a little broader than I would have preferred, but adds a
readonly mode to the transcription and mock model, so that we can
control explicitly when changes are applied to the text store.
Fixes#3620.
Implements the Caps Lock layer support and the double-tap gesture on the
shift key to access it.
The double-tap gesture has been implemented with a view to extension to
support other multi-tap gestures in the future. However, for now, it is
limited to supporting the Shift key, if and only if the keyboard
includes a Caps layer.
The reason for this v15 limitation is that multi-tap on regular keys
would involve either rewinding the previous keystroke (the first tap),
or forcing keyboard developers to consider 'rota' style rules in their
keyboards to support the multi-tap gestures, as we need to make sure
that the first tap is accepted and processed for immediate feedback.
This needs more design, to avoid unnecessary complexity in the keyboards
and/or the rewinding of the keystroke (even though that is conceptually
supported in Keyman Engine for Web already). Basically, we don't want to
constrain the way that a keyboard author may use the multi-tap gesture
by hard-coding the rewind, but neither do we want to make all multi-tap
gestures needlessly complex to author.
The shift key (and other modifiers, potentially in future) needs special
support for multi-tap as the key that is being tapped changes with the
layer change. This is currently managed through recognising `K_SHIFT` in
the key id.
I have tried to follow the `PendingGesture` pattern for multi-tap, and
the gesture itself supports a series of taps, not just a double-tap. The
maximum time to complete the tap series is 125msec * number-of-taps, so
for a double-tap is 250msec.
The changes to support a Caps Lock layer itself were minimal; just
adding the `text.KeyboardProcessor.getStateFromLayer` function and
calling it during `KeyEvent` construction. The remaining changes relate
to the multi-tap gesture.
Minor changes:
* I moved `constructNullKeyEvent` to `KeyEvent` in order to make it
more accessible to other classes.
* The multi-tap gesture does not have a promise to complete, so that is
now an optional member of the `PendingGesture` interface.
Relates to #3621.
Add support for `&layerChanged` system store. This store is set to `1`
before a `begin postKeystroke`, if the keystroke it follows resulted in
a layer change, either programatically through a keyboard rule, or
through a `nextlayer` property of the touched key.
Fixes#5779.
Fixes#5731 (I believe mitigation is sufficient to close this issue).
A variety of interrelated font and font size display issues resolved:
1. KVK font was not applied early enough for size calculations, which
meant that we were calculating font scaling per key based on a
default font when transforming from the KVK data for desktop devices
(defaultLayout.ts)
2. Font scaling for non-default layers was calculated when elements were
not visible and had no size information, giving incorrect values. To
resolve this, font scaling is now calculated when a layer is made
visible, which had performance impacts; resolved by reducing
unnecessary `layer.refreshLayout()` calls; see performance point 1
below (oskView.ts:layerChangeHandler())
3. `getViewportScale()` would return an incorrect scaled value when
emulating touch devices on a desktop browser (kmwutils.ts)
4. After switching keyboards, the device-specific scaling factor was not
maintained (oskView.ts:refreshLayout())
Related performance improvements:
1. Multiple calls to `layer.refreshLayout()` in `refreshLayout()` have
been eliminated, and only the currently visible layer is now
refreshed. This dramatically reduces the number of calls to
`getIdealFontSize()` which was the primary concern of #5731.
(visualKeyboards.ts)
2. Unnecessary use of `innerHTML` replaced with `innerText`
(oskBaseKey.ts)
Minor Keyman Developer performance improvement:
1. The web debugger no longer recalculates the OSK twice (test.js)