Add key coord combos
Added an option to use key coord in the matrix to make combos. this allows to press / release combos regardless of layer and Key.
This commit is contained in:
		
				
					committed by
					
						
						xs5871
					
				
			
			
				
	
			
			
			
						parent
						
							ea3f59340d
						
					
				
				
					commit
					891cd1a67f
				
			@@ -27,6 +27,7 @@ Optional arguments that customize individual combos:
 | 
			
		||||
* `per_key_timeout`: If True, reset timeout on every key press (default for
 | 
			
		||||
  sequences).
 | 
			
		||||
* `timeout`: Set the time window within which the match has to happen in ms.
 | 
			
		||||
* `match_coord`: If True, matches key position in the matrix.
 | 
			
		||||
 | 
			
		||||
## Example Code
 | 
			
		||||
```python
 | 
			
		||||
@@ -43,6 +44,8 @@ make_key(
 | 
			
		||||
combos.combos = [
 | 
			
		||||
    Chord((KC.A, KC.B), KC.LSFT),
 | 
			
		||||
    Chord((KC.A, KC.B, KC.C), KC.LALT),
 | 
			
		||||
    Chord((0, 1), KC.ESC, match_coord=True),
 | 
			
		||||
    Chord((8, 9, 10), KC.MO(4), match_coord=True),
 | 
			
		||||
    Sequence((KC.LEADER, KC.A, KC.B), KC.C),
 | 
			
		||||
    Sequence((KC.E, KC.F), KC.MYKEY, timeout=500, per_key_timeout=False, fast_reset=False)
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
try:
 | 
			
		||||
    from typing import Optional, Tuple
 | 
			
		||||
    from typing import Optional, Tuple, Union
 | 
			
		||||
except ImportError:
 | 
			
		||||
    pass
 | 
			
		||||
from micropython import const
 | 
			
		||||
@@ -24,14 +24,16 @@ class Combo:
 | 
			
		||||
    _remaining = []
 | 
			
		||||
    _timeout = None
 | 
			
		||||
    _state = _ComboState.IDLE
 | 
			
		||||
    _match_coord = False
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        match: Tuple[Key, ...],
 | 
			
		||||
        match: Tuple[Union[Key, int], ...],
 | 
			
		||||
        result: Key,
 | 
			
		||||
        fast_reset=None,
 | 
			
		||||
        per_key_timeout=None,
 | 
			
		||||
        timeout=None,
 | 
			
		||||
        match_coord=None,
 | 
			
		||||
    ):
 | 
			
		||||
        '''
 | 
			
		||||
        match: tuple of keys (KC.A, KC.B)
 | 
			
		||||
@@ -45,22 +47,36 @@ class Combo:
 | 
			
		||||
            self.per_key_timeout = per_key_timeout
 | 
			
		||||
        if timeout is not None:
 | 
			
		||||
            self.timeout = timeout
 | 
			
		||||
        if match_coord is not None:
 | 
			
		||||
            self._match_coord = match_coord
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return f'{self.__class__.__name__}({[k.code for k in self.match]})'
 | 
			
		||||
 | 
			
		||||
    def matches(self, key):
 | 
			
		||||
    def matches(self, key: Key, int_coord: int):
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    def has_match(self, key: Key, int_coord: int):
 | 
			
		||||
        return self._match_coord and int_coord in self.match or key in self.match
 | 
			
		||||
 | 
			
		||||
    def insert(self, key: Key, int_coord: int):
 | 
			
		||||
        if self._match_coord:
 | 
			
		||||
            self._remaining.insert(0, int_coord)
 | 
			
		||||
        else:
 | 
			
		||||
            self._remaining.insert(0, key)
 | 
			
		||||
 | 
			
		||||
    def reset(self):
 | 
			
		||||
        self._remaining = list(self.match)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Chord(Combo):
 | 
			
		||||
    def matches(self, key):
 | 
			
		||||
        if key in self._remaining:
 | 
			
		||||
    def matches(self, key: Key, int_coord: int):
 | 
			
		||||
        if not self._match_coord and key in self._remaining:
 | 
			
		||||
            self._remaining.remove(key)
 | 
			
		||||
            return True
 | 
			
		||||
        elif self._match_coord and int_coord in self._remaining:
 | 
			
		||||
            self._remaining.remove(int_coord)
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
@@ -70,8 +86,12 @@ class Sequence(Combo):
 | 
			
		||||
    per_key_timeout = True
 | 
			
		||||
    timeout = 1000
 | 
			
		||||
 | 
			
		||||
    def matches(self, key):
 | 
			
		||||
        if self._remaining and self._remaining[0] == key:
 | 
			
		||||
    def matches(self, key: Key, int_coord: int):
 | 
			
		||||
        if (
 | 
			
		||||
            not self._match_coord and self._remaining and self._remaining[0] == key
 | 
			
		||||
        ) or (
 | 
			
		||||
            self._match_coord and self._remaining and self._remaining[0] == int_coord
 | 
			
		||||
        ):
 | 
			
		||||
            self._remaining.pop(0)
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
@@ -127,7 +147,7 @@ class Combos(Module):
 | 
			
		||||
        for combo in self.combos:
 | 
			
		||||
            if combo._state != _ComboState.MATCHING:
 | 
			
		||||
                continue
 | 
			
		||||
            if combo.matches(key):
 | 
			
		||||
            if combo.matches(key, int_coord):
 | 
			
		||||
                continue
 | 
			
		||||
            combo._state = _ComboState.IDLE
 | 
			
		||||
            if combo._timeout:
 | 
			
		||||
@@ -182,7 +202,7 @@ class Combos(Module):
 | 
			
		||||
        for combo in self.combos:
 | 
			
		||||
            if combo._state != _ComboState.ACTIVE:
 | 
			
		||||
                continue
 | 
			
		||||
            if key in combo.match:
 | 
			
		||||
            if combo.has_match(key, int_coord):
 | 
			
		||||
                # Deactivate combo if it matches current key.
 | 
			
		||||
                self.deactivate(keyboard, combo)
 | 
			
		||||
 | 
			
		||||
@@ -190,7 +210,7 @@ class Combos(Module):
 | 
			
		||||
                    self.reset_combo(keyboard, combo)
 | 
			
		||||
                    self._key_buffer = []
 | 
			
		||||
                else:
 | 
			
		||||
                    combo._remaining.insert(0, key)
 | 
			
		||||
                    combo.insert(key, int_coord)
 | 
			
		||||
                    combo._state = _ComboState.MATCHING
 | 
			
		||||
 | 
			
		||||
                key = combo.result
 | 
			
		||||
@@ -203,7 +223,7 @@ class Combos(Module):
 | 
			
		||||
            for combo in self.combos:
 | 
			
		||||
                if combo._state != _ComboState.MATCHING:
 | 
			
		||||
                    continue
 | 
			
		||||
                if key not in combo.match:
 | 
			
		||||
                if not combo.has_match(key, int_coord):
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                # Combo matches, but first key released before timeout.
 | 
			
		||||
@@ -216,7 +236,7 @@ class Combos(Module):
 | 
			
		||||
                    if combo.fast_reset:
 | 
			
		||||
                        self.reset_combo(keyboard, combo)
 | 
			
		||||
                    else:
 | 
			
		||||
                        combo._remaining.insert(0, key)
 | 
			
		||||
                        combo.insert(key, int_coord)
 | 
			
		||||
                        combo._state = _ComboState.MATCHING
 | 
			
		||||
                    self.reset(keyboard)
 | 
			
		||||
 | 
			
		||||
@@ -236,7 +256,7 @@ class Combos(Module):
 | 
			
		||||
 | 
			
		||||
                # Anything between first and last key released.
 | 
			
		||||
                else:
 | 
			
		||||
                    combo._remaining.insert(0, key)
 | 
			
		||||
                    combo.insert(key, int_coord)
 | 
			
		||||
 | 
			
		||||
            # Don't propagate key-release events for keys that have been
 | 
			
		||||
            # buffered. Append release events only if corresponding press is in
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user