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

Add support for Key Overrides #409

Open
rrotter opened this issue Apr 20, 2022 · 2 comments
Open

Add support for Key Overrides #409

rrotter opened this issue Apr 20, 2022 · 2 comments

Comments

@rrotter
Copy link
Contributor

rrotter commented Apr 20, 2022

Key Overrides in QMK allow remapping a key based upon which mods the user is holding. This allows, for example, switching the shift layer to produce different symbols, or swapping a base key with its shifted variant.

Docs for QMK implementation

@xs5871
Copy link
Collaborator

xs5871 commented May 25, 2022

Could be done with combos. We're missing some knobs for combos anyway and I'm currently working on making this possible as a side effect.

@kilipan
Copy link

kilipan commented Mar 14, 2023

I've written this for my own usage, maybe someone more versed in python object orientation and kmk's internal logic could refactor it into something like a module? (in an oop-implementation you'd also probably get rid of the need for a global variable)

from kmk.keys import KC, make_key


mods_before_modmorph = set()
def modmorph(names = {'DUMMY_KEY',}, default_kc = KC.NO, morphed_kc = KC.NO, triggers = {KC.LSHIFT, KC.RSHIFT}):
    def _pressed(key, state, KC, *args, **kwargs):
        global mods_before_modmorph
        mods_before_modmorph = triggers.intersection(state.keys_pressed)
        # if a trigger is held, morph key
        if mods_before_modmorph:
            state._send_hid()
            for mod_kc in mods_before_modmorph:
                # discard triggering mods so morphed key is unaffected by them
                state.keys_pressed.discard(mod_kc)
            state.keys_pressed.add(morphed_kc)
            state.hid_pending = True
            return state
        # else return default keycode
        state.keys_pressed.add(default_kc)
        state.hid_pending = True
        return state
    def _released(key, state, KC, *args, **kwargs):
        if {morphed_kc,}.intersection(state.keys_pressed):
            state.keys_pressed.discard(morphed_kc)
            for mod_kc in mods_before_modmorph:
                # re-add previously discarded shift so normal typing isn't impacted
                state.keys_pressed.add(mod_kc)
        else:
            state.keys_pressed.discard(default_kc)
        state.hid_pending = True
        return state
    modmorph_key = make_key(names=names, on_press=_pressed,
                            on_release=_released)
    return modmorph_key

Define a mod morph / key override for e.g. a comma/semicolon key like this:

modmorph({'CSEM', 'COMMA_SEMICOLON'}, KC.COMMA, KC.SEMICOLON)

Then simply use the chosen keycode (here: KC.CSEM or KC.COMMA_SEMICOLON) in your keymap.

[Edits: Improve clarity]

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

No branches or pull requests

3 participants