Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Conditional module/extension #956

Open
p3lim opened this issue Apr 1, 2024 · 3 comments
Open

[Enhancement] Conditional module/extension #956

p3lim opened this issue Apr 1, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@p3lim
Copy link

p3lim commented Apr 1, 2024

Is your feature request related to a problem? Please describe.

I use a lot of keys that depend on other keys being pressed, and the closest solution to this in KMK that I've found is to create a a bunch of custom key like this:

from kmk.keys import make_key

def on_pressed(key, keyboard, KC, *args, **kwargs):
  SPACE = {KC.SPACE}
  if SPACE.intersection(keyboard.keys_pressed):
    keyboard.keys_pressed.add(KC.A)
  else:
    keyboard.keys_pressed.add(KC.B)
  keyboard.hid_pending = True
  return keyboard

def on_released(key, keyboard, KC, *args, **kwargs):
  keyboard.keys_pressed.discard(KC.A)
  keyboard.keys_pressed.discard(KC.B)
  keyboard.hid_pending = True
  return keyboard

make_key(names=('SPAB'), on_press=on_pressed, on_release=on_released)

Describe the solution you'd like

A module/extension that makes this easier. Using the same example keys as above:

# syntax:
#  if   key(s)     then  else
KC.CK((KC.SPACE,), KC.A, KC.B)

This might be very specific to my usecase, so it's understandable if it gets denied, I just want to clean up my messy main.py 😄.

@p3lim p3lim added the enhancement New feature or request label Apr 1, 2024
@p3lim p3lim changed the title [Enhancement] Title [Enhancement] Conditional module/extension Apr 1, 2024
@p3lim
Copy link
Author

p3lim commented Apr 1, 2024

Thinking maybe something as simple as this?

from kmk.keys import make_argumented_key
from kmk.modules import Module

class ConditionalKeyMeta:
	def __init__(self, mods, key1, key2): # could use some type checks
		self.mods = set(mods)
		self.key1 = key1
		self.key2 = key2

class ConditionalKey(Module):
	def __init__(self):
		make_argumented_key(
			names=('CK',),
			validator=ConditionalKeyMeta,
		)

	def during_bootup(self, keyboard):
		return

	def before_matrix_scan(self, keyboard):
		return

	def after_matrix_scan(self, keyboard):
		return

	def process_key(self, keyboard):
		if is_pressed:
			if self.meta.mods.intersection(keyboard.keys_pressed):
				key = self.meta.key1
			else:
				key = self.meta.key2
		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

Haven't made a module before, my knowledge of KMK is still new, and I'm currently unable to test if it works as my new keyboard I will put KMK on hasn't arrived just yet.

@xs5871
Copy link
Collaborator

xs5871 commented Apr 3, 2024

You're basically asking for a "ModMorph" or "KeyOverride" kind of module.
I had that in my pipeline for a year and been using an mvp similar to yours. But when I got to thinking about unit tests and all the edge cases it got burried in the maybe-later pile.

@b2ox
Copy link
Contributor

b2ox commented May 6, 2024

I have modified the code to make it work.

from kmk.keys import make_argumented_key
from kmk.modules import Module

class ConditionalKeyMeta:
    def __init__(self, mods, keyThen, keyElse):
        self.mods = set(mods)
        self.keyThen = keyThen
        self.keyElse = keyElse

class ConditionalKey(Module):
    def __init__(self):
        make_argumented_key(
            names=('CK',),
            validator=ConditionalKeyMeta,
        )

    def during_bootup(self, keyboard):
        return

    def before_matrix_scan(self, keyboard):
        return

    def after_matrix_scan(self, keyboard):
        return

    def process_key(self, keyboard, key, is_pressed, int_coord):
        if not isinstance(key.meta, ConditionalKeyMeta):
            return key

        if key.meta.mods.issubset(keyboard.keys_pressed):
            return key.meta.keyThen

        return key.meta.keyElse

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants