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