KMKfw / kmk_firmware

Clackety Keyboards Powered by Python
https://kmkfw.zulipchat.com
Other
1.32k stars 457 forks source link

[Enhancement] Layer timeouts #946

Open bradezard131 opened 3 months ago

bradezard131 commented 3 months ago

Is your feature request related to a problem? Please describe. I have a habit of walking away from my keyboard while in a layer, usually my function/nav layer, and then coming back 5-10 minutes later without remembering that I'm in a layer. This causes rather chaotic results when I start pressing F-keys in rapid succession.

Describe the solution you'd like A layer timeout similar to CapsWord, where after a configurable time of inactivity the layer will deactivate. A well configured timeout would completely remove this issue, and a default of no timeout would prevent this from affecting existing users who may be happy with existing behaviour.

Describe alternatives you've considered I have a KC.TO set up to reset everything manually, but it's rather clunky and I regularly forget to do it. I could also use momentary layer activation but holding down my layer key while I navigate around with arrows hasn't been a great experience either.

Additional context I can probably figure this implementation out myself if need be, so I'd be interested in knowing if the project would be willing to receive a PR for it even if nobody else wants to work on it.

xs5871 commented 3 months ago

Here's an untested blueprint how this could look like:

new module inactivity.py

from kmk.modules import Module
from kmk.scheduler import cancel_task, create_task

class Inactivity(Module):
    def __init__(self, timeout, action):
        self.timeout = timeout
        self.action = action

    def during_bootup(self, keyboard):
        self._task = create_task(action(keyboard), after_ms=timeout)

    def before_matrix_scan(self, keyboard):
        return

    def process_key(self, keyboard, key, is_pressed, int_coord):
        cancel_task(self._task)
        self._task = create_task(action, after_ms=self.timeout)
        return key

    def before_hid_send(self, keyboard):
        return

    def after_hid_send(self, keyboard):
        return

    def on_powersave_enable(self, keyboard):
        return

    def on_powersave_disable(self, keyboard):
        return

    def after_matrix_scan(self, keyboard):
        return

in main.py

# ...
from inactivity import Inactivity

def reset_layers(keyboard):
    def _():
        keyboard.active_layers.clear()
        layers.activate_layer(keyboard, 0)

    return _

keyboard.modules.append( 
    Inactivity(timeout=60 * 1000, action=reset_layers)
)

The name "Inactivity" isn't great. Was too lazy to come up with something more descriptive.

If you test that and write some documentation we'll accept a PR.