feat(web): Caps Layer and double-tap gesture 🕊#5989
Conversation
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.
User Test ResultsTest specification and instructions 🟥 SUITE_BASELINE: Test that nothing has changed in existing keyboards
🟥 SUITE_CAPS: Test that the new Caps Lock layer controls work correctly
Test Artifacts |
Removed the 'heuristic' test as it is probably not appropriate for testing. Removed the mobile-specific platform from the touch layout as it did not include a caps layer (and should have been identical to the tablet one anyway).
ermshiperete
left a comment
There was a problem hiding this comment.
Didn't see anything obvious, but my knowledge in that part of the code is pretty limited 😄
| } | ||
|
|
||
| /** | ||
| * Get state key state from layer id |
There was a problem hiding this comment.
Is the double state intentional?
There was a problem hiding this comment.
Yes, on 101 key keyboards, the 'state' keys are the caps lock, num lock, scroll lock keys, but we only care about Caps Lock. So this is retrieving the state of these keys 😆.
Both getStateFromLayer and getModifierState above could be better; right now a layer called "foolscapsymbols" (okay, it's a stretch) would also be considered a 'caps lock' layer.
| c this is a heuristic: if we find two+ characters in capitals, leave | ||
| c us in shift layer, assuming the user hasn't just switched layer | ||
| c themselves. Not sure if this is a good idea! | ||
| c if(&layerChanged = "0") if(&layer = 'shift') any(caps) any(caps) > layer('caps') c ??? is this a good idea? |
There was a problem hiding this comment.
do you want to keep this comment?
There was a problem hiding this comment.
Perhaps I should probably remove that heuristic altogether? I will leave it for now but think about it for a follow-up PR.
SUITE_BASELINE: Test that nothing has changed in existing keyboards
|
This video no longer appears available? |
This may not be related to this change; can we do a screenshare test together on this? @keymanapp-test-bot retest SUITE_BASELINE TEST_BASELINE_ANDROID |
Screen_Recording_20211214-155720_Keyman.mp4 |
SUITE_BASELINE: Test that nothing has changed in existing keyboards
|
SUITE_CAPS: Test that the new Caps Lock layer controls work correctly
Screen_Recording_20211220-104706_Keyman.mp4 |
SUITE_CAPS: Test that the new Caps Lock layer controls work correctly
|
SUITE_CAPS: Test that the new Caps Lock layer controls work correctly
Screen.Recording.2021-12-20.at.1.20.41.PM.mov
|
SUITE_CAPS: Test that the new Caps Lock layer controls work correctly
|
|
Failing test feedback:
As I have now captured the three failure cases as separate issues, I will go ahead and merge this PR, with the caveat that these issues must be resolved before release. |
|
Changes in this pull request will be available for download in Keyman version 15.0.180-alpha |
|
How to enable CAPS LOCK with double tap in Keyboard? |
|
I have tried in iOS 15.0.188-alpha with EUROSIL |
|
I tested full_caps_3620_3621.zip with iOS 15.0.188-alpha CAPS lock turns off, after a key stroke |
|
@MakaraSok or @bharanidharanj, are you able to replicate the issues that @MayuraVerma has experienced? Can you work with Mayura to build a reproducible test case so we can resolve this before release? |
The SIL Eurolatin keyboard has not yet been updated to support Caps Lock 😄 |
Yes, I realized it later. since then I tested full_caps_3620_3621.zip with iOS 15.0.188-alpha Capslock works. But I am thinking we are leaving it to the keyboard developer to choose the next layer after output in CAPS layer, default should be it should remain in CAPS layer. Once we enter CAPS layer, only why to get out of CAPS layer should be release the CAPS lock. This is how it works in hardware, we should mimic the same in software keyboard also. |
My earlier assumption was, web/ios/android picks up the NCAPS state from kmn. looks like we need to rewrite it mobile version. |
Yeah, unfortunately given how the touch and physical keyboards diverge, we could not find a safe way to do this automatically. My preference is always to give the control to the keyboard designer, in any case -- but the trade-off is that we don't get this kind of behaviour "for free". |
There are two ways, in our design, that the Caps Lock layer is released on touch:
So if you are seeing behaviour that does not match those conditions, that is definitely a bug. And if you can give repro steps, that will help us squash the bug! |





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_SHIFTin the key id.I have tried to follow the
PendingGesturepattern 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.getStateFromLayerfunction and calling it duringKeyEventconstruction. The remaining changes relate to the multi-tap gesture.Minor changes:
constructNullKeyEventtoKeyEventin order to make it more accessible to other classes.PendingGestureinterface.Note:
User Testing
SUITE_BASELINE: Test that nothing has changed in existing keyboards
SUITE_CAPS: Test that the new Caps Lock layer controls work correctly