Merge pull request #47 from KMKfw/topic-leader-mode-clean
@kdb424's Leader Mode Enter work as a clean diff
This commit is contained in:
commit
64888f1df8
@ -143,3 +143,10 @@ class UnicodeModes:
|
|||||||
LINUX = IBUS = 1
|
LINUX = IBUS = 1
|
||||||
MACOS = OSX = RALT = 2
|
MACOS = OSX = RALT = 2
|
||||||
WINC = 3
|
WINC = 3
|
||||||
|
|
||||||
|
|
||||||
|
class LeaderMode:
|
||||||
|
Default = 0
|
||||||
|
Default_Active = 1
|
||||||
|
Enter = 2
|
||||||
|
Enter_Active = 3
|
||||||
|
@ -25,7 +25,6 @@ InitFirmware = namedtuple('InitFirmware', (
|
|||||||
'row_pins',
|
'row_pins',
|
||||||
'col_pins',
|
'col_pins',
|
||||||
'diode_orientation',
|
'diode_orientation',
|
||||||
'unicode_mode',
|
|
||||||
))
|
))
|
||||||
|
|
||||||
KeyUpDown = namedtuple('KeyUpDown', ('type', 'row', 'col'))
|
KeyUpDown = namedtuple('KeyUpDown', ('type', 'row', 'col'))
|
||||||
@ -34,14 +33,13 @@ NewMatrix = namedtuple('NewMatrix', ('type', 'matrix'))
|
|||||||
BareEvent = namedtuple('BareEvent', ('type',))
|
BareEvent = namedtuple('BareEvent', ('type',))
|
||||||
|
|
||||||
|
|
||||||
def init_firmware(keymap, row_pins, col_pins, diode_orientation, unicode_mode):
|
def init_firmware(keymap, row_pins, col_pins, diode_orientation):
|
||||||
return InitFirmware(
|
return InitFirmware(
|
||||||
type=INIT_FIRMWARE_EVENT,
|
type=INIT_FIRMWARE_EVENT,
|
||||||
keymap=keymap,
|
keymap=keymap,
|
||||||
row_pins=row_pins,
|
row_pins=row_pins,
|
||||||
col_pins=col_pins,
|
col_pins=col_pins,
|
||||||
diode_orientation=diode_orientation,
|
diode_orientation=diode_orientation,
|
||||||
unicode_mode=unicode_mode,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from kmk.common import kmktime
|
from kmk.common import kmktime
|
||||||
from kmk.common.consts import DiodeOrientation, UnicodeModes
|
from kmk.common.consts import DiodeOrientation, LeaderMode, UnicodeModes
|
||||||
from kmk.common.event_defs import (HID_REPORT_EVENT, INIT_FIRMWARE_EVENT,
|
from kmk.common.event_defs import (HID_REPORT_EVENT, INIT_FIRMWARE_EVENT,
|
||||||
KEY_DOWN_EVENT, KEY_UP_EVENT,
|
KEY_DOWN_EVENT, KEY_UP_EVENT,
|
||||||
KEYCODE_DOWN_EVENT, KEYCODE_UP_EVENT,
|
KEYCODE_DOWN_EVENT, KEYCODE_UP_EVENT,
|
||||||
@ -69,28 +69,31 @@ class InternalState:
|
|||||||
keys_pressed = set()
|
keys_pressed = set()
|
||||||
pending_keys = set()
|
pending_keys = set()
|
||||||
macro_pending = None
|
macro_pending = None
|
||||||
|
leader_pending = None
|
||||||
|
leader_last_len = 0
|
||||||
hid_pending = False
|
hid_pending = False
|
||||||
unicode_mode = UnicodeModes.NOOP
|
|
||||||
tap_time = 300
|
|
||||||
keymap = []
|
keymap = []
|
||||||
row_pins = []
|
row_pins = []
|
||||||
col_pins = []
|
col_pins = []
|
||||||
matrix = []
|
matrix = []
|
||||||
diode_orientation = DiodeOrientation.COLUMNS
|
diode_orientation = DiodeOrientation.COLUMNS
|
||||||
|
leader_mode_history = []
|
||||||
active_layers = [0]
|
active_layers = [0]
|
||||||
start_time = {
|
start_time = {
|
||||||
'lt': None,
|
'lt': None,
|
||||||
'tg': None,
|
'tg': None,
|
||||||
'tt': None,
|
'tt': None,
|
||||||
}
|
'lm': None,
|
||||||
tick_time = {
|
'leader': None,
|
||||||
'lt': None,
|
|
||||||
'tg': None,
|
|
||||||
'tt': None,
|
|
||||||
}
|
}
|
||||||
_oldstates = []
|
_oldstates = []
|
||||||
|
|
||||||
def __init__(self, preserve_intermediate_states=False):
|
def __init__(self, preserve_intermediate_states=False):
|
||||||
|
import kmk_keyboard_user
|
||||||
|
self.unicode_mode = getattr(kmk_keyboard_user, 'unicode_mode', UnicodeModes.NOOP)
|
||||||
|
self.tap_time = getattr(kmk_keyboard_user, 'tap_time', 300)
|
||||||
|
self.leader_mode = getattr(kmk_keyboard_user, 'leader_mode', LeaderMode.Enter)
|
||||||
|
self.LEADER_DICTIONARY = getattr(kmk_keyboard_user, 'LEADER_DICTIONARY', {})
|
||||||
self.preserve_intermediate_states = preserve_intermediate_states
|
self.preserve_intermediate_states = preserve_intermediate_states
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
@ -105,8 +108,8 @@ class InternalState:
|
|||||||
'active_layers': self.active_layers,
|
'active_layers': self.active_layers,
|
||||||
'unicode_mode': self.unicode_mode,
|
'unicode_mode': self.unicode_mode,
|
||||||
'tap_time': self.tap_time,
|
'tap_time': self.tap_time,
|
||||||
|
'leader_mode_history': self.leader_mode_history,
|
||||||
'start_time': self.start_time,
|
'start_time': self.start_time,
|
||||||
'tick_time': self.tick_time,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
@ -196,18 +199,19 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
state.matrix = action.matrix
|
state.matrix = action.matrix
|
||||||
state.keys_pressed |= pressed
|
state.keys_pressed |= pressed
|
||||||
state.keys_pressed -= released
|
state.keys_pressed -= released
|
||||||
state.hid_pending = True
|
if state.leader_mode % 2 == 1:
|
||||||
|
state.hid_pending = False
|
||||||
|
else:
|
||||||
|
state.hid_pending = True
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
if action.type == KEYCODE_UP_EVENT:
|
if action.type == KEYCODE_UP_EVENT:
|
||||||
state.keys_pressed.discard(action.keycode)
|
state.keys_pressed.discard(action.keycode)
|
||||||
state.hid_pending = True
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
if action.type == KEYCODE_DOWN_EVENT:
|
if action.type == KEYCODE_DOWN_EVENT:
|
||||||
state.keys_pressed.add(action.keycode)
|
state.keys_pressed.add(action.keycode)
|
||||||
state.hid_pending = True
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
if action.type == INIT_FIRMWARE_EVENT:
|
if action.type == INIT_FIRMWARE_EVENT:
|
||||||
@ -216,7 +220,6 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
row_pins=action.row_pins,
|
row_pins=action.row_pins,
|
||||||
col_pins=action.col_pins,
|
col_pins=action.col_pins,
|
||||||
diode_orientation=action.diode_orientation,
|
diode_orientation=action.diode_orientation,
|
||||||
unicode_mode=action.unicode_mode,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# HID events are non-mutating, used exclusively for listeners to know
|
# HID events are non-mutating, used exclusively for listeners to know
|
||||||
@ -224,7 +227,6 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
# into KEY_UP_EVENT and KEY_DOWN_EVENT, but for now it's nice to separate
|
# into KEY_UP_EVENT and KEY_DOWN_EVENT, but for now it's nice to separate
|
||||||
# this out for debugging's sake.
|
# this out for debugging's sake.
|
||||||
if action.type == HID_REPORT_EVENT:
|
if action.type == HID_REPORT_EVENT:
|
||||||
state.hid_pending = False
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
if action.type == MACRO_COMPLETE_EVENT:
|
if action.type == MACRO_COMPLETE_EVENT:
|
||||||
@ -268,6 +270,8 @@ def process_internal_key_event(state, action_type, changed_key, logger=None):
|
|||||||
return unicode_mode(state, action_type, changed_key, logger=logger)
|
return unicode_mode(state, action_type, changed_key, logger=logger)
|
||||||
elif changed_key.code == RawKeycodes.KC_MACRO:
|
elif changed_key.code == RawKeycodes.KC_MACRO:
|
||||||
return macro(state, action_type, changed_key, logger=logger)
|
return macro(state, action_type, changed_key, logger=logger)
|
||||||
|
elif changed_key.code == Keycodes.KMK.KC_LEAD.code:
|
||||||
|
return leader(state)
|
||||||
else:
|
else:
|
||||||
return state
|
return state
|
||||||
|
|
||||||
@ -410,3 +414,12 @@ def macro(state, action_type, changed_key, logger):
|
|||||||
return state
|
return state
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
def leader(state):
|
||||||
|
if state.leader_mode % 2 == 0:
|
||||||
|
state.keys_pressed.discard(Keycodes.KMK.KC_LEAD)
|
||||||
|
# All leader modes are one number higher when activating
|
||||||
|
state.leader_mode += 1
|
||||||
|
|
||||||
|
return state
|
||||||
|
86
kmk/common/leader_mode.py
Normal file
86
kmk/common/leader_mode.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from kmk.common.keycodes import Keycodes
|
||||||
|
|
||||||
|
|
||||||
|
class LeaderHelper:
|
||||||
|
"""
|
||||||
|
Acts as a hid to absorb keypress, and perform macros when a timer
|
||||||
|
or enter key is pressed depending on the mode set.
|
||||||
|
"""
|
||||||
|
def __init__(self, store, log_level=logging.NOTSET):
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.logger.setLevel(log_level)
|
||||||
|
|
||||||
|
self.store = store
|
||||||
|
self.store.subscribe(
|
||||||
|
lambda state, action: self._subscription(state, action),
|
||||||
|
)
|
||||||
|
|
||||||
|
def _subscription(self, state, action):
|
||||||
|
"""
|
||||||
|
Subscribes to the state machine, and dispatches actions based
|
||||||
|
based on incoming keypresses, or when a timer runs out depending
|
||||||
|
on the mode.
|
||||||
|
:param state:
|
||||||
|
:param action:
|
||||||
|
:return state:
|
||||||
|
"""
|
||||||
|
if state.leader_mode % 2 == 1:
|
||||||
|
keys_pressed = state.keys_pressed
|
||||||
|
|
||||||
|
if state.leader_last_len and state.leader_mode_history:
|
||||||
|
history_set = set(state.leader_mode_history)
|
||||||
|
|
||||||
|
keys_pressed = keys_pressed - history_set
|
||||||
|
|
||||||
|
state.leader_last_len = len(state.keys_pressed)
|
||||||
|
|
||||||
|
for key in keys_pressed:
|
||||||
|
if key == Keycodes.Common.KC_ENT:
|
||||||
|
# Process the action and remove the extra KC.ENT that was added to get here
|
||||||
|
state = process(state)
|
||||||
|
return clean_exit(state)
|
||||||
|
elif key == Keycodes.Common.KC_ESC:
|
||||||
|
# Clean state and turn leader mode off.
|
||||||
|
return clean_exit(state)
|
||||||
|
elif key == Keycodes.KMK.KC_LEAD:
|
||||||
|
return state
|
||||||
|
else:
|
||||||
|
# Add key if not needing to escape
|
||||||
|
# This needs replaced later with a proper debounce
|
||||||
|
state.leader_mode_history.append(key)
|
||||||
|
return state
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
def clean_exit(state):
|
||||||
|
"""
|
||||||
|
Cleans up the state and hands the HID control back.
|
||||||
|
:param state:
|
||||||
|
:return state:
|
||||||
|
"""
|
||||||
|
state.leader_mode_history = []
|
||||||
|
state.leader_mode -= 1
|
||||||
|
state.leader_last_len = 0
|
||||||
|
state.keys_pressed.clear()
|
||||||
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
def process(state):
|
||||||
|
"""
|
||||||
|
Checks if there are iny matching sequences of keys, and
|
||||||
|
performs the macro specified by the user.
|
||||||
|
:param state:
|
||||||
|
:param leader_dictionary:
|
||||||
|
:return state:
|
||||||
|
"""
|
||||||
|
lmh = tuple(state.leader_mode_history)
|
||||||
|
|
||||||
|
if lmh in state.LEADER_DICTIONARY:
|
||||||
|
state.macro_pending = state.LEADER_DICTIONARY[lmh].keydown
|
||||||
|
|
||||||
|
state.keys_pressed.clear()
|
||||||
|
|
||||||
|
return state
|
@ -1,19 +1,28 @@
|
|||||||
import sys
|
import sys
|
||||||
from logging import DEBUG
|
|
||||||
|
|
||||||
from kmk.common.consts import UnicodeModes
|
import gc
|
||||||
|
|
||||||
from kmk.firmware import Firmware
|
from kmk.firmware import Firmware
|
||||||
from kmk.micropython.matrix import MatrixScanner
|
from kmk.micropython.matrix import MatrixScanner
|
||||||
from kmk.micropython.pyb_hid import HIDHelper
|
from kmk.micropython.pyb_hid import HIDHelper
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
from kmk_keyboard_user import cols, diode_orientation, keymap, rows
|
import kmk_keyboard_user
|
||||||
|
cols = getattr(kmk_keyboard_user, 'cols')
|
||||||
|
diode_orientation = getattr(kmk_keyboard_user, 'diode_orientation')
|
||||||
|
keymap = getattr(kmk_keyboard_user, 'keymap')
|
||||||
|
rows = getattr(kmk_keyboard_user, 'rows')
|
||||||
|
|
||||||
try:
|
DEBUG_ENABLE = getattr(kmk_keyboard_user, 'DEBUG_ENABLE', False)
|
||||||
from kmk_keyboard_user import unicode_mode
|
|
||||||
except Exception:
|
if DEBUG_ENABLE:
|
||||||
unicode_mode = UnicodeModes.NOOP
|
from logging import DEBUG
|
||||||
|
else:
|
||||||
|
from logging import ERROR as DEBUG
|
||||||
|
|
||||||
|
# This will run out of ram at this point unless you manually GC
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
firmware = Firmware(
|
firmware = Firmware(
|
||||||
@ -21,11 +30,12 @@ def main():
|
|||||||
row_pins=rows,
|
row_pins=rows,
|
||||||
col_pins=cols,
|
col_pins=cols,
|
||||||
diode_orientation=diode_orientation,
|
diode_orientation=diode_orientation,
|
||||||
unicode_mode=unicode_mode,
|
|
||||||
hid=HIDHelper,
|
hid=HIDHelper,
|
||||||
log_level=DEBUG,
|
log_level=DEBUG,
|
||||||
matrix_scanner=MatrixScanner,
|
matrix_scanner=MatrixScanner,
|
||||||
)
|
)
|
||||||
|
# This will run out of ram at this point unless you manually GC
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
firmware.go()
|
firmware.go()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -2,14 +2,16 @@ import logging
|
|||||||
|
|
||||||
from kmk.common.event_defs import init_firmware
|
from kmk.common.event_defs import init_firmware
|
||||||
from kmk.common.internal_state import Store, kmk_reducer
|
from kmk.common.internal_state import Store, kmk_reducer
|
||||||
|
from kmk.common.leader_mode import LeaderHelper
|
||||||
|
|
||||||
|
|
||||||
class Firmware:
|
class Firmware:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, keymap, row_pins, col_pins,
|
self, keymap, row_pins, col_pins,
|
||||||
diode_orientation, unicode_mode=None,
|
diode_orientation, unicode_mode=None,
|
||||||
hid=None, log_level=logging.NOTSET,
|
hid=None,
|
||||||
matrix_scanner=None,
|
log_level=logging.NOTSET,
|
||||||
|
matrix_scanner=None,
|
||||||
):
|
):
|
||||||
assert matrix_scanner is not None
|
assert matrix_scanner is not None
|
||||||
self.matrix_scanner = matrix_scanner
|
self.matrix_scanner = matrix_scanner
|
||||||
@ -32,12 +34,13 @@ class Firmware:
|
|||||||
"Board will run in debug mode",
|
"Board will run in debug mode",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.leader_helper = LeaderHelper(store=self.store, log_level=log_level)
|
||||||
|
|
||||||
self.store.dispatch(init_firmware(
|
self.store.dispatch(init_firmware(
|
||||||
keymap=keymap,
|
keymap=keymap,
|
||||||
row_pins=row_pins,
|
row_pins=row_pins,
|
||||||
col_pins=col_pins,
|
col_pins=col_pins,
|
||||||
diode_orientation=diode_orientation,
|
diode_orientation=diode_orientation,
|
||||||
unicode_mode=unicode_mode,
|
|
||||||
))
|
))
|
||||||
|
|
||||||
def _subscription(self, state, action):
|
def _subscription(self, state, action):
|
||||||
|
@ -34,6 +34,6 @@ class HIDHelper(AbstractHidHelper):
|
|||||||
# It'd be real awesome if pyb.USB_HID.send/recv would support
|
# It'd be real awesome if pyb.USB_HID.send/recv would support
|
||||||
# uselect.poll or uselect.select to more safely determine when
|
# uselect.poll or uselect.select to more safely determine when
|
||||||
# it is safe to write to the host again...
|
# it is safe to write to the host again...
|
||||||
delay(5)
|
delay(1)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from kmk.common.consts import DiodeOrientation, UnicodeModes
|
from kmk.common.consts import DiodeOrientation, LeaderMode, UnicodeModes
|
||||||
from kmk.common.keycodes import KC
|
from kmk.common.keycodes import KC
|
||||||
from kmk.common.macros.unicode import unicode_sequence
|
from kmk.common.macros.unicode import unicode_sequence
|
||||||
from kmk.common.pins import Pin as P
|
from kmk.common.pins import Pin as P
|
||||||
@ -9,9 +9,14 @@ rows = (P.Y1, P.Y2, P.Y3, P.Y4)
|
|||||||
|
|
||||||
diode_orientation = DiodeOrientation.COLUMNS
|
diode_orientation = DiodeOrientation.COLUMNS
|
||||||
|
|
||||||
unicode_mode = UnicodeModes.LINUX
|
|
||||||
tap_time = 180
|
|
||||||
|
|
||||||
|
# ------------------User level config variables ---------------------------------------
|
||||||
|
unicode_mode = UnicodeModes.LINUX
|
||||||
|
tap_time = 150
|
||||||
|
leader_timeout = 2000
|
||||||
|
DEBUG_ENABLE = True
|
||||||
|
|
||||||
|
# -------------------------------Macros -----------------------------------------------
|
||||||
FLIP = unicode_sequence([
|
FLIP = unicode_sequence([
|
||||||
"28",
|
"28",
|
||||||
"30ce",
|
"30ce",
|
||||||
@ -26,13 +31,74 @@ FLIP = unicode_sequence([
|
|||||||
"253b",
|
"253b",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
# ---------------------- Leader Key Macros --------------------------------------------
|
||||||
|
|
||||||
|
LEADER_DICTIONARY = {
|
||||||
|
(KC.F, KC.L, KC.I, KC.P):
|
||||||
|
unicode_sequence([
|
||||||
|
"28",
|
||||||
|
"30ce",
|
||||||
|
"ca0",
|
||||||
|
"75ca",
|
||||||
|
"ca0",
|
||||||
|
"29",
|
||||||
|
"30ce",
|
||||||
|
"5f61",
|
||||||
|
"253b",
|
||||||
|
"2501",
|
||||||
|
"253b",
|
||||||
|
]),
|
||||||
|
(KC.C, KC.H, KC.E, KC.E, KC.R):
|
||||||
|
unicode_sequence([
|
||||||
|
'002B',
|
||||||
|
'FF61',
|
||||||
|
'003A',
|
||||||
|
'002E',
|
||||||
|
'FF9F',
|
||||||
|
'30FD',
|
||||||
|
'0028',
|
||||||
|
'00B4',
|
||||||
|
'2200',
|
||||||
|
'FF61',
|
||||||
|
'0029',
|
||||||
|
'FF89',
|
||||||
|
'FF9F',
|
||||||
|
'002E',
|
||||||
|
'003A',
|
||||||
|
'FF61',
|
||||||
|
'002B',
|
||||||
|
'FF9F',
|
||||||
|
'FF9F',
|
||||||
|
'002B',
|
||||||
|
'FF61',
|
||||||
|
'003A',
|
||||||
|
'002E',
|
||||||
|
'FF9F',
|
||||||
|
'30FD',
|
||||||
|
'0028',
|
||||||
|
'002A',
|
||||||
|
'00B4',
|
||||||
|
'2200',
|
||||||
|
'0029',
|
||||||
|
'FF89',
|
||||||
|
'FF9F',
|
||||||
|
'002E',
|
||||||
|
'003A',
|
||||||
|
'FF61',
|
||||||
|
'002B',
|
||||||
|
'FF9F',
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------- Keymap ---------------------------------------------------------
|
||||||
|
|
||||||
keymap = [
|
keymap = [
|
||||||
[
|
[
|
||||||
# Default
|
# Default
|
||||||
[KC.GESC, KC.QUOTE, KC.COMMA, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BKSP],
|
[KC.GESC, KC.QUOTE, KC.COMMA, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BKSP],
|
||||||
[KC.TAB, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT],
|
[KC.TAB, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT],
|
||||||
[KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH],
|
[KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH],
|
||||||
[KC.LCTRL, KC.LGUI, KC.LALT, KC.NO, KC.MO(2), KC.LT(3, KC.SPC), KC.LT(3, KC.SPC), KC.MO(4), KC.LEFT, KC.DOWN, KC.UP, KC.RIGHT],
|
[KC.LCTRL, KC.LGUI, KC.LALT, KC.LEAD, KC.MO(2), KC.LT(3, KC.SPC), KC.LT(3, KC.SPC), KC.MO(4), KC.LEFT, KC.DOWN, KC.UP, KC.RIGHT],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
# Gaming
|
# Gaming
|
||||||
|
Loading…
x
Reference in New Issue
Block a user