Capslock behavior
This Caps Lock behavior provides ways to create improved, configurable Caps Lock keys.
Unlike sending a regular &kp CAPSLOCK which blindly toggles caps lock, this behavior uses the HID indicator state to predictably set caps lock regardless of the current status on the connected device (basically it will send &kp CAPSLOCK if toggling is needed but do nothing if the current state already matches the target state).
The main motivation is to provide an alternative &capsword that uses caps lock instead of shift modifiers but there are a few additional configuration that could be sensible:
-
&capslock_onenables caps lock -
&capslock_offdisables caps lock -
&capslock_holdenables caps lock and disables it when released -
&capslock_wordenables caps lock, and disables it when a word separator is typed or the key is pressed again
This PR supersedes #1485 where I naively proposed to replace the current shift-based &capsword, which turned out to be misguided. The shift-based version does have issues (layout compatibility) but this capslock-based version does have its own too (OS compatibility).
It seems like we can't have the one true way and we should provide both and let user pick between "good and wrong" &capsword (using shift modifiers works transparently across OS, but not across layouts because shift isn't actually the same thing as capitalization) and "right and bad" &capslock_word (caps lock does proper capitalization across layouts, but its activation/deactivation does not work transparently across all OS due to their various implementation quirks) depending on their use-case.
- It feels like this one behavior driver does a lot of related, but very different things. Is this intended to allow for different combinations of configuration that don't exist in the predefined behaviors?
Yes, this is a capslock behavior driver that just happens to allow for some implementation of "caps word" (by automatically deactivating capslock after a configurable word separator has been typed). But other use cases are (include? I don't know maybe there's more):
- you want 2 separate keys for turning capslock on and off, instead of the single
&kp CAPSLOCKthat toggles it - you want a capslock key that doesn't actually lock and is only active when held, kindof how a modifier works
Maybe I went about it wrong with them implementation, it seemed straightforward to me to have the various activation/deactivation conditions exposed in the behavior and combine them in the behavior instances (not sure about the terminology here, sorry). I'm all ears is there is a more proper way to do it.
Would it be better to pull some of the caps lock handling out into core functions that can be called from anywhere?
That would also be great but from the few times it's been mentioned (previous PR, Discord), capslock is quirky enough across various OS (Mac has a minimum keypress duration, some user may have remapped/disabled the key altogether, ...) that that may be a hard/risky thing to do. I'm all for it if you have a solution there.
- Having it also handle "capslock word" means that it could easily get out of sync with
&caps_word. It would be nice to have feature parity, especially if PRs like Bring caps word to feature parity with QMK #1742 get accepted and they end up only applying to one of the two implementations.Then I think it would be possible to use the existing
&caps_wordbehavior, add a new property to it that tells it to hold caps lock, and setmods = <0>(or have that done automatically when caps lock mod is enabled) to get the existing behavior to use caps lock instead of shift.
I believe looking at the two versions as alternative implementations of the same feature is a red herring. Even though there is obviously a huge apparent overlap they are actually two diametrically opposite features:
- shift-based version emulates capitalization on the keyboard. This is great because the shifting mechanism is standard across OS, but it requires to be layout-aware to implement the capitalization logic (configuring
continue-listand possibly other proposed exceptions and workarounds, see #1470, #1479, #1478) - capslock-based version delegates capitalization to the OS. This is great because the OS already knows about capitalization logic across layouts, but it requires to be OS/device-aware because activating/deactivating capslock is surprisingly not standard (for Mac you need to set
capslock-press-duration = <95>, if you swapped the capslock and escape key you'd need to configurecapslock-press-keycodeaccordingly)
I'm also not convinced you can achieve feature parity between the two versions in the first place.
For example on an AZERTY keyboard èçàù shifts to 790%, with capslock it capitalizes to ÈÇÀÙ (see this comment on previous PR) and I don't think you can emulate that with modifiers.
I didn't mean feature parity with regards to making sure that &caps_word produces the same output with modifiers as it does with caps lock (if that were possible, then you wouldn't be creating a version of it that uses caps lock to begin with). I meant with regards to how it determines when it's hit the end of a word, idle timeouts, etc.
I didn't mean feature parity with regards to making sure that
&caps_wordproduces the same output with modifiers as it does with caps lock (if that were possible, then you wouldn't be creating a version of it that uses caps lock to begin with). I meant with regards to how it determines when it's hit the end of a word, idle timeouts, etc.
Ok, I see, that make sense, I did not need to type this whole novel in the end :D
I think we're going to have to disagree on the "end of word" configuration though. &caps_word gets away with having a partial continue-list because of the hardcoded QWERTY assumption; while the whole point of using capslock is not having to know or care about the layout: pressing the &capslock_word key ensures capslock is on (toggles it only if needed), and then does nothing until one of the given stop keys is pressed, at which point it ensures capslock is off (toggles it only if needed).
The fact the capslock version sits and waits for the time to deactivate, as opposed to the shift version which has to actively modify most keys is enough of a conceptual difference to warrant different configuration modes IMO