Reformat type hints to use comment style syntax

Update Pipfile to add typing module and pyright
Update pyproject.toml for pyright and mypy configs
This commit is contained in:
sofubi 2021-08-27 00:33:28 -04:00
parent 9fc431e0a7
commit b202dc77d1
12 changed files with 439 additions and 311 deletions

View File

@ -21,4 +21,6 @@ black = "==21.6b0"
flake8-quotes = "*" flake8-quotes = "*"
flake8-black = "*" flake8-black = "*"
circuitpython-stubs = "==7.0.0a6.dev195" circuitpython-stubs = "==7.0.0a6.dev195"
pyright = "*"
typing = "*"
mypy = "*" mypy = "*"

131
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "e80d827684ac8c56b762a74548440c5b371c5b3ee5fcb5b74e68ae6d9bff0665" "sha256": "cee0eeba8c8dad66dccffe0935656829132f7ca928569e3aa957f278e6e92da6"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": {}, "requires": {},
@ -94,11 +94,11 @@
}, },
"flake8-comprehensions": { "flake8-comprehensions": {
"hashes": [ "hashes": [
"sha256:b07aef3277623db32310aa241a1cec67212b53c1d18e767d7e26d4d83aa05bf7", "sha256:4888de89248b7f7535159189ff693c77f8354f6d37a02619fa28c9921a913aa0",
"sha256:f24be9032587127f7a5bc6d066bf755b6e66834f694383adb8a673e229c1f559" "sha256:e9a010b99aa90c05790d45281ad9953df44a4a08a1a8f6cd41f98b4fc6a268a0"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.5.0" "version": "==3.6.1"
}, },
"flake8-isort": { "flake8-isort": {
"hashes": [ "hashes": [
@ -110,10 +110,10 @@
}, },
"flake8-quotes": { "flake8-quotes": {
"hashes": [ "hashes": [
"sha256:3f1116e985ef437c130431ac92f9b3155f8f652fda7405ac22ffdfd7a9d1055e" "sha256:f1dd87830ed77ff2ce47fc0ee0fd87ae20e8f045355354ffbf4dcaa18d528217"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.2.0" "version": "==3.3.0"
}, },
"greenlet": { "greenlet": {
"hashes": [ "hashes": [
@ -300,6 +300,13 @@
"index": "pypi", "index": "pypi",
"version": "==0.3.1" "version": "==0.3.1"
}, },
"nodeenv": {
"hashes": [
"sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
"sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
],
"version": "==1.6.0"
},
"parso": { "parso": {
"hashes": [ "hashes": [
"sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398", "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398",
@ -332,11 +339,11 @@
}, },
"prompt-toolkit": { "prompt-toolkit": {
"hashes": [ "hashes": [
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f", "sha256:6076e46efae19b1e0ca1ec003ed37a933dc94b4d20f486235d436e64771dcd5c",
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88" "sha256:eb71d5a6b72ce6db177af4a7d4d7085b99756bf656d98ffcc4fecd36850eea6c"
], ],
"markers": "python_full_version >= '3.6.1'", "markers": "python_full_version >= '3.6.2'",
"version": "==3.0.19" "version": "==3.0.20"
}, },
"ptyprocess": { "ptyprocess": {
"hashes": [ "hashes": [
@ -363,11 +370,11 @@
}, },
"pygments": { "pygments": {
"hashes": [ "hashes": [
"sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f", "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380",
"sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e" "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
], ],
"markers": "python_version >= '3.5'", "markers": "python_version >= '3.5'",
"version": "==2.9.0" "version": "==2.10.0"
}, },
"pynvim": { "pynvim": {
"hashes": [ "hashes": [
@ -375,6 +382,14 @@
], ],
"version": "==0.4.3" "version": "==0.4.3"
}, },
"pyright": {
"hashes": [
"sha256:dd8e18c54321340be44a708b6037c0b967486c32b3f492741fffdc205cb82f15",
"sha256:e2668730cddf580e696d4a11946e740e2f5647df1eb45f7c55b7029376eac5a1"
],
"index": "pypi",
"version": "==0.0.9"
},
"pyserial": { "pyserial": {
"hashes": [ "hashes": [
"sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb",
@ -408,41 +423,49 @@
}, },
"regex": { "regex": {
"hashes": [ "hashes": [
"sha256:026beb631097a4a3def7299aa5825e05e057de3c6d72b139c37813bfa351274b", "sha256:0696eb934dee723e3292056a2c046ddb1e4dd3887685783a9f4af638e85dee76",
"sha256:14caacd1853e40103f59571f169704367e79fb78fac3d6d09ac84d9197cadd16", "sha256:105122fa63da98d8456d5026bc6ac5a1399fd82fa6bad22c6ea641b1572c9142",
"sha256:16d9eaa8c7e91537516c20da37db975f09ac2e7772a0694b245076c6d68f85da", "sha256:116c277774f84266044e889501fe79cfd293a8b4336b7a5e89b9f20f1e5a9f21",
"sha256:18fdc51458abc0a974822333bd3a932d4e06ba2a3243e9a1da305668bd62ec6d", "sha256:12eaf0bbe568bd62e6cade7937e0bf01a2a4cef49a82f4fd204401e78409e158",
"sha256:28e8af338240b6f39713a34e337c3813047896ace09d51593d6907c66c0708ba", "sha256:1401cfa4320691cbd91191ec678735c727dee674d0997b0902a5a38ad482faf5",
"sha256:3835de96524a7b6869a6c710b26c90e94558c31006e96ca3cf6af6751b27dca1", "sha256:19acdb8831a4e3b03b23369db43178d8fee1f17b99c83af6cd907886f76bd9d4",
"sha256:3905c86cc4ab6d71635d6419a6f8d972cab7c634539bba6053c47354fd04452c", "sha256:208851a2f8dd31e468f0b5aa6c94433975bd67a107a4e7da3bdda947c9f85e25",
"sha256:3c09d88a07483231119f5017904db8f60ad67906efac3f1baa31b9b7f7cca281", "sha256:24d68499a27b2d93831fde4a9b84ea5b19e0ab141425fbc9ab1e5b4dad179df7",
"sha256:4551728b767f35f86b8e5ec19a363df87450c7376d7419c3cac5b9ceb4bce576", "sha256:2778c6cb379d804e429cc8e627392909e60db5152b42c695c37ae5757aae50ae",
"sha256:459bbe342c5b2dec5c5223e7c363f291558bc27982ef39ffd6569e8c082bdc83", "sha256:2a0a5e323cf86760784ce2b91d8ab5ea09d0865d6ef4da0151e03d15d097b24e",
"sha256:4f421e3cdd3a273bace013751c345f4ebeef08f05e8c10757533ada360b51a39", "sha256:2d9cbe0c755ab8b6f583169c0783f7278fc6b195e423b09c5a8da6f858025e96",
"sha256:577737ec3d4c195c4aef01b757905779a9e9aee608fa1cf0aec16b5576c893d3", "sha256:2de1429e4eeab799c168a4f6e6eecdf30fcaa389bba4039cc8a065d6b7aad647",
"sha256:57fece29f7cc55d882fe282d9de52f2f522bb85290555b49394102f3621751ee", "sha256:32753eda8d413ce4f208cfe01dd61171a78068a6f5d5f38ccd751e00585cdf1d",
"sha256:7976d410e42be9ae7458c1816a416218364e06e162b82e42f7060737e711d9ce", "sha256:3ee8ad16a35c45a5bab098e39020ecb6fec3b0e700a9d88983d35cbabcee79c8",
"sha256:85f568892422a0e96235eb8ea6c5a41c8ccbf55576a2260c0160800dbd7c4f20", "sha256:4f03fc0a25122cdcbf39136510d4ea7627f732206892db522adf510bc03b8c67",
"sha256:8764a78c5464ac6bde91a8c87dd718c27c1cabb7ed2b4beaf36d3e8e390567f9", "sha256:4f3e36086d6631ceaf468503f96a3be0d247caef0660c9452fb1b0c055783851",
"sha256:8935937dad2c9b369c3d932b0edbc52a62647c2afb2fafc0c280f14a8bf56a6a", "sha256:503c1ba0920a46a1844363725215ef44d59fcac2bd2c03ae3c59aa9d08d29bd6",
"sha256:8fe58d9f6e3d1abf690174fd75800fda9bdc23d2a287e77758dc0e8567e38ce6", "sha256:507861cf3d97a86fbe26ea6cc04660ae028b9e4080b8290e28b99547b4e15d89",
"sha256:937b20955806381e08e54bd9d71f83276d1f883264808521b70b33d98e4dec5d", "sha256:56ae6e3cf0506ec0c40b466e31f41ee7a7149a2b505ae0ee50edd9043b423d27",
"sha256:9569da9e78f0947b249370cb8fadf1015a193c359e7e442ac9ecc585d937f08d", "sha256:6530b7b9505123cdea40a2301225183ca65f389bc6129f0c225b9b41680268d8",
"sha256:a3b73390511edd2db2d34ff09aa0b2c08be974c71b4c0505b4a048d5dc128c2b", "sha256:6729914dd73483cd1c8aaace3ac082436fc98b0072743ac136eaea0b3811d42f",
"sha256:a4eddbe2a715b2dd3849afbdeacf1cc283160b24e09baf64fa5675f51940419d", "sha256:7406dd2e44c7cfb4680c0a45a03264381802c67890cf506c147288f04c67177d",
"sha256:a5c6dbe09aff091adfa8c7cfc1a0e83fdb8021ddb2c183512775a14f1435fe16", "sha256:7684016b73938ca12d160d2907d141f06b7597bd17d854e32bb7588be01afa1d",
"sha256:b63e3571b24a7959017573b6455e05b675050bbbea69408f35f3cb984ec54363", "sha256:7db58ad61f3f6ea393aaf124d774ee0c58806320bc85c06dc9480f5c7219c250",
"sha256:bb350eb1060591d8e89d6bac4713d41006cd4d479f5e11db334a48ff8999512f", "sha256:83946ca9278b304728b637bc8d8200ab1663a79de85e47724594917aeed0e892",
"sha256:bf6d987edd4a44dd2fa2723fca2790f9442ae4de2c8438e53fcb1befdf5d823a", "sha256:84057cfae5676f456b03970eb78b7e182fddc80c2daafd83465a3d6ca9ff8dbf",
"sha256:bfa6a679410b394600eafd16336b2ce8de43e9b13f7fb9247d84ef5ad2b45e91", "sha256:862b6164e9a38b5c495be2c2854e75fd8af12c5be4c61dc9b42d255980d7e907",
"sha256:c856ec9b42e5af4fe2d8e75970fcc3a2c15925cbcc6e7a9bcb44583b10b95e80", "sha256:8ddb4f9ce6bb388ecc97b4b3eb37e786f05d7d5815e8822e0d87a3dbd7100649",
"sha256:cea56288eeda8b7511d507bbe7790d89ae7049daa5f51ae31a35ae3c05408531", "sha256:92eb03f47427fea452ff6956d11f5d5a3f22a048c90a0f34fa223e6badab6c85",
"sha256:ea212df6e5d3f60341aef46401d32fcfded85593af1d82b8b4a7a68cd67fdd6b", "sha256:a5f3bc727fea58f21d99c22e6d4fca652dc11dbc2a1e7cfc4838cd53b2e3691f",
"sha256:f35567470ee6dbfb946f069ed5f5615b40edcbb5f1e6e1d3d2b114468d505fc6", "sha256:a6180dbf5945b27e9420e1b58c3cacfc79ad5278bdad3ea35109f5680fbe16d1",
"sha256:fbc20975eee093efa2071de80df7f972b7b35e560b213aafabcec7c0bd00bd8c", "sha256:b158f673ae6a6523f13704f70aa7e4ce875f91e379bece4362c89db18db189d5",
"sha256:ff4a8ad9638b7ca52313d8732f37ecd5fd3c8e3aff10a8ccb93176fd5b3812f6" "sha256:cd45b4542134de63e7b9dd653e0a2d7d47ffed9615e3637c27ca5f6b78ea68bb",
"sha256:d2404336fd16788ea757d4218a2580de60adb052d9888031e765320be8884309",
"sha256:db888d4fb33a2fd54b57ac55d5015e51fa849f0d8592bd799b4e47f83bd04e00",
"sha256:dde0ac721c7c5bfa5f9fc285e811274dec3c392f2c1225f7d07ca98a8187ca84",
"sha256:de0d06ccbc06af5bf93bddec10f4f80275c5d74ea6d28b456931f3955f58bc8c",
"sha256:e02dad60e3e8442eefd28095e99b2ac98f2b8667167493ac6a2f3aadb5d84a17",
"sha256:e960fe211496333b2f7e36badf4c22a919d740386681f79139ee346b403d1ca1",
"sha256:e9700c52749cb3e90c98efd72b730c97b7e4962992fca5fbcaf1363be8e3b849",
"sha256:ee318974a1fdacba1701bc9e552e9015788d6345416364af6fa987424ff8df53"
], ],
"version": "==2021.8.3" "version": "==2021.8.27"
}, },
"s3cmd": { "s3cmd": {
"hashes": [ "hashes": [
@ -462,10 +485,10 @@
}, },
"testfixtures": { "testfixtures": {
"hashes": [ "hashes": [
"sha256:9bddf79b2dddb36420a20c25a65c827a8e7398c6ed4e2c75c2697857cb006be9", "sha256:0a6422737f6d89b45cdef1e2df5576f52ad0f507956002ce1020daa9f44211d6",
"sha256:d4bd1c4f90eac90a73e1bdc59c31d03943f218d687f3c5a09e48478841a8af5f" "sha256:486be7b01eb71326029811878a3317b7e7994324621c0ec633c8e24499d8d5b3"
], ],
"version": "==6.18.0" "version": "==6.18.1"
}, },
"toml": { "toml": {
"hashes": [ "hashes": [
@ -483,6 +506,14 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==5.0.5" "version": "==5.0.5"
}, },
"typing": {
"hashes": [
"sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9",
"sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5"
],
"index": "pypi",
"version": "==3.7.4.3"
},
"typing-extensions": { "typing-extensions": {
"hashes": [ "hashes": [
"sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497", "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",

View File

@ -11,3 +11,17 @@ class UnicodeMode:
LINUX = IBUS = const(1) LINUX = IBUS = const(1)
MACOS = OSX = RALT = const(2) MACOS = OSX = RALT = const(2)
WINC = const(3) WINC = const(3)
TYPING_PLATFORMS = [
'linux',
'linux2',
'win32',
'cygwin',
'msys',
'darwin',
'freebsd7',
'freebsd8',
'freebsdN',
'openbsd6',
]

View File

@ -1,16 +1,21 @@
from kmk.kmk_keyboard import KMKKeyboard
class InvalidExtensionEnvironment(Exception): class InvalidExtensionEnvironment(Exception):
pass pass
class Extension: class Extension:
_enabled = True _enabled = True # type: bool
def enable(self, keyboard): def enable(self, keyboard):
# type: (KMKKeyboard) -> None
self._enabled = True self._enabled = True
self.on_runtime_enable(keyboard) self.on_runtime_enable(keyboard)
def disable(self, keyboard): def disable(self, keyboard):
# type (KMKKeyboard) -> None
self._enabled = False self._enabled = False
self.on_runtime_disable(keyboard) self.on_runtime_disable(keyboard)
@ -18,34 +23,43 @@ class Extension:
# The below methods should be implemented by subclasses # The below methods should be implemented by subclasses
def on_runtime_enable(self, keyboard): def on_runtime_enable(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def on_runtime_disable(self, keyboard): def on_runtime_disable(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def during_bootup(self, keyboard): def during_bootup(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def before_matrix_scan(self, keyboard): def before_matrix_scan(self, keyboard):
# type: (KMKKeyboard) -> None
''' '''
Return value will be injected as an extra matrix update Return value will be injected as an extra matrix update
''' '''
raise NotImplementedError raise NotImplementedError
def after_matrix_scan(self, keyboard): def after_matrix_scan(self, keyboard):
# type: (KMKKeyboard) -> None
''' '''
Return value will be replace matrix update if supplied Return value will be replace matrix update if supplied
''' '''
raise NotImplementedError raise NotImplementedError
def before_hid_send(self, keyboard): def before_hid_send(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def after_hid_send(self, keyboard): def after_hid_send(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def on_powersave_enable(self, keyboard): def on_powersave_enable(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError
def on_powersave_disable(self, keyboard): def on_powersave_disable(self, keyboard):
# type: (KMKKeyboard) -> None
raise NotImplementedError raise NotImplementedError

View File

@ -1,6 +1,7 @@
'''Adds international keys''' '''Adds international keys'''
from kmk.extensions import Extension from kmk.extensions import Extension
from kmk.keys import make_key from kmk.keys import make_key
from kmk.kmk_keyboard import KMKKeyboard
class International(Extension): class International(Extension):
@ -32,28 +33,37 @@ class International(Extension):
make_key(code=152, names=('LANG9',)) make_key(code=152, names=('LANG9',))
def on_runtime_enable(self, sandbox): def on_runtime_enable(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def on_runtime_disable(self, sandbox): def on_runtime_disable(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def during_bootup(self, sandbox): def during_bootup(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def before_matrix_scan(self, sandbox): def before_matrix_scan(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def after_matrix_scan(self, sandbox): def after_matrix_scan(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def before_hid_send(self, sandbox): def before_hid_send(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def after_hid_send(self, sandbox): def after_hid_send(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def on_powersave_enable(self, sandbox): def on_powersave_enable(self, sandbox):
# type: (KMKKeyboard) -> None
return return
def on_powersave_disable(self, sandbox): def on_powersave_disable(self, sandbox):
# type: (KMKKeyboard) -> None
return return

View File

@ -1,23 +1,29 @@
from typing import Any, Optional import sys
from kmk.keys import Key, KeyAttrDict from kmk.consts import TYPING_PLATFORMS
from kmk.kmk_keyboard import KMKKeyboard
from kmk.kmktime import sleep_ms from kmk.kmktime import sleep_ms
if sys.platform in TYPING_PLATFORMS:
from typing import Any, Optional
from kmk.keys import Key, KeyAttrDict
from kmk.kmk_keyboard import KMKKeyboard # Avoid cyclical imports
def passthrough(key, keyboard, *args, **kwargs): def passthrough(key, keyboard, *args, **kwargs):
return keyboard return keyboard
def default_pressed( def default_pressed(
key: Key, key, # type: Key
keyboard: KMKKeyboard, keyboard, # type: KMKKeyboard
KC: KeyAttrDict, KC, # type: KeyAttrDict
coord_int: Optional[int] = None, coord_int=None, # type: Optional[int]
coord_raw: Optional[str] = None, coord_raw=None, # type: Optional[str]
*args: Any, *args, # type: Any
**kwargs: Any, **kwargs, # type: Any
) -> KMKKeyboard: ):
# type: (...) -> KMKKeyboard
keyboard.hid_pending = True keyboard.hid_pending = True
if coord_int is not None: if coord_int is not None:
@ -29,14 +35,15 @@ def default_pressed(
def default_released( def default_released(
key: Key, key, # type: Key
keyboard: KMKKeyboard, keyboard, # type: KMKKeyboard
KC: KeyAttrDict, KC, # type: KeyAttrDict
coord_int: Optional[int] = None, coord_int=None, # type: Optional[int]
coord_raw: Optional[str] = None, coord_raw=None, # type: Optional[str]
*args: Any, *args, # type: Any
**kwargs: Any, # NOQA **kwargs, # type: Any # NOQA
): ):
# type: (...) -> KMKKeyboard
keyboard.hid_pending = True keyboard.hid_pending = True
keyboard.keys_pressed.discard(key) keyboard.keys_pressed.discard(key)

View File

@ -1,6 +1,6 @@
from typing import List, Optional import sys
from kmk.keys import Key from kmk.consts import TYPING_PLATFORMS
from kmk.types import ( from kmk.types import (
KeySeqSleepMeta, KeySeqSleepMeta,
LayerKeyMeta, LayerKeyMeta,
@ -9,12 +9,20 @@ from kmk.types import (
UnicodeModeKeyMeta, UnicodeModeKeyMeta,
) )
if sys.platform in TYPING_PLATFORMS:
from typing import List, Optional
def key_seq_sleep_validator(ms: float) -> KeySeqSleepMeta: # Avoid cyclical imports
from kmk.keys import Key
def key_seq_sleep_validator(ms):
# type: (float) -> KeySeqSleepMeta
return KeySeqSleepMeta(ms) return KeySeqSleepMeta(ms)
def layer_key_validator(layer: int, kc: Key = None) -> LayerKeyMeta: def layer_key_validator(layer, kc=None):
# type: (int, Optional[Key]) -> LayerKeyMeta
''' '''
Validates the syntax (but not semantics) of a layer key call. We won't Validates the syntax (but not semantics) of a layer key call. We won't
have access to the keymap here, so we can't verify much of anything useful have access to the keymap here, so we can't verify much of anything useful
@ -25,16 +33,19 @@ def layer_key_validator(layer: int, kc: Key = None) -> LayerKeyMeta:
return LayerKeyMeta(layer=layer, kc=kc) return LayerKeyMeta(layer=layer, kc=kc)
def mod_tap_validator(kc: Key, mods: Optional[List[Key]] = None) -> ModTapKeyMeta: def mod_tap_validator(kc, mods):
# type: (Key, Optional[List[Key]]) -> ModTapKeyMeta
''' '''
Validates that mod tap keys are correctly used Validates that mod tap keys are correctly used
''' '''
return ModTapKeyMeta(kc=kc, mods=mods) return ModTapKeyMeta(kc=kc, mods=mods)
def tap_dance_key_validator(*codes: Key) -> TapDanceKeyMeta: def tap_dance_key_validator(*codes):
# type: (*Key) -> TapDanceKeyMeta
return TapDanceKeyMeta(codes) return TapDanceKeyMeta(codes)
def unicode_mode_key_validator(mode: int) -> UnicodeModeKeyMeta: def unicode_mode_key_validator(mode):
# type: (int) -> UnicodeModeKeyMeta
return UnicodeModeKeyMeta(mode) return UnicodeModeKeyMeta(mode)

View File

@ -1,43 +1,37 @@
from __future__ import annotations
import gc import gc
from micropython import const from micropython import const
from typing import Any, Callable, List, Optional, Protocol, Set, Tuple, Union import sys
import kmk.handlers.stock as handlers import kmk.handlers.stock as handlers
from kmk.consts import UnicodeMode from kmk.consts import TYPING_PLATFORMS, UnicodeMode
from kmk.key_validators import ( from kmk.key_validators import (
key_seq_sleep_validator, key_seq_sleep_validator,
tap_dance_key_validator, tap_dance_key_validator,
unicode_mode_key_validator, unicode_mode_key_validator,
) )
from kmk.kmk_keyboard import KMKKeyboard
from kmk.types import AttrDict, UnicodeModeKeyMeta from kmk.types import AttrDict, UnicodeModeKeyMeta
DEBUG_OUTPUT: bool = False if sys.platform in TYPING_PLATFORMS:
from typing import Any, Callable, List, Optional, Set, Tuple, Union
FIRST_KMK_INTERNAL_KEY: int = const(1000) # Avoid cyclical imports
NEXT_AVAILABLE_KEY: int = 1000 from kmk.kmk_keyboard import KMKKeyboard
KEY_SIMPLE: int = const(0)
KEY_MODIFIER: int = const(1)
KEY_CONSUMER: int = const(2)
ALL_ALPHAS: str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' DEBUG_OUTPUT = False # type: bool
ALL_NUMBERS: str = '1234567890'
FIRST_KMK_INTERNAL_KEY = const(1000) # type: int
NEXT_AVAILABLE_KEY = 1000 # type: int
KEY_SIMPLE = const(0) # type: int
KEY_MODIFIER = const(1) # type: int
KEY_CONSUMER = const(2) # type: int
ALL_ALPHAS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # type: str
ALL_NUMBERS = '1234567890' # type: str
# since KC.1 isn't valid Python, alias to KC.N1 # since KC.1 isn't valid Python, alias to KC.N1
ALL_NUMBER_ALIASES: Tuple[str, ...] = tuple(f'N{x}' for x in ALL_NUMBERS) ALL_NUMBER_ALIASES = tuple(f'N{x}' for x in ALL_NUMBERS) # type: Tuple[str, ...]
KeyReturn = Union[Key, ModifierKey, ConsumerKey, None]
class LeftPipeCallback(Protocol):
def __call__(
self, candidate: str, code: Union[str, int], names: Tuple[str, ...]
) -> KeyReturn:
...
class InfiniteLoopDetected(Exception): class InfiniteLoopDetected(Exception):
@ -47,10 +41,11 @@ class InfiniteLoopDetected(Exception):
# this is a bit of an FP style thing - combining a pipe operator a-la F# with # this is a bit of an FP style thing - combining a pipe operator a-la F# with
# a bootleg Maybe monad to clean up these make_key sequences # a bootleg Maybe monad to clean up these make_key sequences
def left_pipe_until_some( def left_pipe_until_some(
candidate: str, candidate, # type: str
functor: LeftPipeCallback, functor, # type: Callable[[str, Union[str, int], Tuple[str, ...]], Optional[Union[Key, ModifierKey, ConsumerKey]]]
*args_iter: Tuple[Union[str, int], Tuple[str, ...]], *args_iter, # type: Tuple[Union[str, int], Tuple[str, ...]]
) -> KeyReturn: ):
# type: (...) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
for args in args_iter: for args in args_iter:
result = functor(candidate, *args) result = functor(candidate, *args)
if result is not None: if result is not None:
@ -58,41 +53,43 @@ def left_pipe_until_some(
def first_truthy( def first_truthy(
candidate: str, candidate, # type: str
*funcs: Callable[[str], Union[Key, ModifierKey, ConsumerKey, None]], *funcs, # type: Callable[[str], Union[Key, ModifierKey, ConsumerKey, None]]
) -> KeyReturn: ):
# type: (...) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
for func in funcs: for func in funcs:
result = func(candidate) result = func(candidate)
if result is not None: if result is not None:
return result return result
def maybe_make_mod_key(candidate: str, code: int, names: Tuple[str, ...]) -> KeyReturn: def maybe_make_mod_key(candidate, code, names):
# type: (str, int, Tuple[str, ...]) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
if candidate in names: if candidate in names:
return make_mod_key(code=code, names=names) return make_mod_key(code=code, names=names)
def maybe_make_key(candidate: str, code: int, names: Tuple[str, ...]) -> KeyReturn: def maybe_make_key(candidate, code, names):
# type: (str, int, Tuple[str, ...]) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
if candidate in names: if candidate in names:
return make_key(code=code, names=names) return make_key(code=code, names=names)
def maybe_make_shifted_key( def maybe_make_shifted_key(candidate, target_name, names):
candidate: str, target_name: str, names: Tuple[str, ...] # type: (str, str, Tuple[str, ...]) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
) -> KeyReturn:
if candidate in names: if candidate in names:
return make_shifted_key(target_name=target_name, names=names) return make_shifted_key(target_name=target_name, names=names)
def maybe_make_consumer_key( def maybe_make_consumer_key(candidate, code, names):
candidate: str, code: int, names: Tuple[str, ...] # type: (str, int, Tuple[str, ...]) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
) -> KeyReturn:
if candidate in names: if candidate in names:
return make_consumer_key(code=code, names=names) return make_consumer_key(code=code, names=names)
class KeyAttrDict(AttrDict): class KeyAttrDict(AttrDict):
def __getattr__(self, key: str, depth: int = 0) -> KeyReturn: def __getattr__(self, key, depth=0):
# type: (str, int) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
if depth > 1: if depth > 1:
raise InfiniteLoopDetected() raise InfiniteLoopDetected()
@ -410,54 +407,46 @@ class KeyAttrDict(AttrDict):
KC = KeyAttrDict() KC = KeyAttrDict()
class DefaultPressRelease(Protocol):
def __call__(
self,
key: Key,
keyboard: KMKKeyboard,
KC: KeyAttrDict,
coord_int: Optional[int],
coord_raw: Optional[str],
*args: Any,
**kwargs: Any,
) -> KMKKeyboard:
...
Handler = Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]
HandlerList = List[Handler]
class Key: class Key:
def __init__( def __init__(
self, self,
code: int, code, # type: int
has_modifiers: Optional[Set[int]] = None, has_modifiers=None, # type: Optional[Set[int]]
no_press: Optional[bool] = False, no_press=False, # type: bool
no_release: Optional[bool] = False, no_release=False, # type: bool
on_press: DefaultPressRelease = handlers.default_pressed, on_press=handlers.default_pressed, # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
on_release: DefaultPressRelease = handlers.default_released, on_release=handlers.default_released, # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
meta: object = object(), meta=object(), # type: object
) -> None: ):
self.code: int = code # type: (...) -> None
self.has_modifiers: Optional[Set[int]] = has_modifiers self.code = code # type: int
self.has_modifiers = has_modifiers # type: Optional[Set[int]]
# cast to bool() in case we get a None value # cast to bool() in case we get a None value
self.no_press: bool = bool(no_press) self.no_press = bool(no_press) # type: bool
self.no_release: bool = bool(no_press) self.no_release = bool(no_press) # type: bool
self._pre_press_handlers: HandlerList = [] self._pre_press_handlers = (
self._post_press_handlers: HandlerList = [] []
self._pre_release_handlers: HandlerList = [] ) # type: List[Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]]
self._post_release_handlers: HandlerList = [] self._post_press_handlers = (
self._handle_press: DefaultPressRelease = on_press []
self._handle_release: DefaultPressRelease = on_release ) # type: List[Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]]
self.meta: object = meta self._pre_release_handlers = (
[]
) # type: List[Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]]
self._post_release_handlers = (
[]
) # type: List[Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]]
self._handle_press = (
on_press
) # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
self._handle_release = (
on_release
) # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
self.meta = meta # type: object
def __call__( def __call__(self, no_press, no_release):
self, no_press: Optional[bool] = None, no_release: Optional[bool] = None # type: (Optional[bool], Optional[bool]) -> Key
) -> Key:
if no_press is None and no_release is None: if no_press is None and no_release is None:
return self return self
@ -469,37 +458,43 @@ class Key:
) )
def __repr__(self): def __repr__(self):
# type: () -> str
return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers) return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers)
def on_press( def on_press(self, state, coord_int, coord_raw):
self, state: KMKKeyboard, coord_int: int, coord_raw: str # type: (KMKKeyboard, int, str) -> Optional[Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]]
) -> Union[KMKKeyboard, None]:
for fn in self._pre_press_handlers: for fn in self._pre_press_handlers:
if not fn(self, state, KC, coord_int, coord_raw): if not fn(self, state, KC, coord_int, coord_raw):
return None return None
ret = self._handle_press(self, state, KC, coord_int, coord_raw) # TODO -- SOFUBI -- look into way to type hint *args and **kwargs of a Callable signature
ret = self._handle_press(
self, state, KC, coord_int, coord_raw
) # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
for fn in self._post_press_handlers: for fn in self._post_press_handlers:
fn(self, state, KC, coord_int, coord_raw) fn(self, state, KC, coord_int, coord_raw)
return ret return ret
def on_release( def on_release(self, state, coord_int, coord_raw):
self, state: KMKKeyboard, coord_int: int, coord_raw: str # type: (KMKKeyboard, int, str) -> Optional[Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]]
) -> Union[KMKKeyboard, None]:
for fn in self._pre_release_handlers: for fn in self._pre_release_handlers:
if not fn(self, state, KC, coord_int, coord_raw): if not fn(self, state, KC, coord_int, coord_raw):
return None return None
ret = self._handle_release(self, state, KC, coord_int, coord_raw) # TODO -- SOFUBI -- look into way to type hint *args and **kwargs of a Callable signature
ret = self._handle_release(
self, state, KC, coord_int, coord_raw
) # type: Callable[[Key, KMKKeyboard, KeyAttrDict, Optional[int], Optional[str], Any, Any], KMKKeyboard]
for fn in self._post_release_handlers: for fn in self._post_release_handlers:
fn(self, state, KC, coord_int, coord_raw) fn(self, state, KC, coord_int, coord_raw)
return ret return ret
def clone(self) -> Key: def clone(self):
# type: () -> Key
''' '''
Return a shallow clone of the current key without any pre/post press/release Return a shallow clone of the current key without any pre/post press/release
handlers attached. Almost exclusively useful for creating non-colliding keys handlers attached. Almost exclusively useful for creating non-colliding keys
@ -516,7 +511,8 @@ class Key:
meta=self.meta, meta=self.meta,
) )
def before_press_handler(self, fn: Handler) -> Key: def before_press_handler(self, fn):
# type: (Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]) -> Key
''' '''
Attach a callback to be run prior to the on_press handler for this key. Attach a callback to be run prior to the on_press handler for this key.
Receives the following: Receives the following:
@ -540,7 +536,8 @@ class Key:
self._pre_press_handlers.append(fn) self._pre_press_handlers.append(fn)
return self return self
def after_press_handler(self, fn: Handler) -> Key: def after_press_handler(self, fn):
# type: (Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]) -> Key
''' '''
Attach a callback to be run after the on_release handler for this key. Attach a callback to be run after the on_release handler for this key.
Receives the following: Receives the following:
@ -563,7 +560,8 @@ class Key:
self._post_press_handlers.append(fn) self._post_press_handlers.append(fn)
return self return self
def before_release_handler(self, fn: Handler) -> Key: def before_release_handler(self, fn):
# type: (Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]) -> Key
''' '''
Attach a callback to be run prior to the on_release handler for this Attach a callback to be run prior to the on_release handler for this
key. Receives the following: key. Receives the following:
@ -587,7 +585,8 @@ class Key:
self._pre_release_handlers.append(fn) self._pre_release_handlers.append(fn)
return self return self
def after_release_handler(self, fn: Handler) -> Key: def after_release_handler(self, fn):
# type: (Callable[[Any, KMKKeyboard, KeyAttrDict, int, str], KMKKeyboard]) -> Key
''' '''
Attach a callback to be run after the on_release handler for this key. Attach a callback to be run after the on_release handler for this key.
Receives the following: Receives the following:
@ -615,14 +614,15 @@ class ModifierKey(Key):
# FIXME this is atrocious to read. Please, please, please, strike down upon # FIXME this is atrocious to read. Please, please, please, strike down upon
# this with great vengeance and furious anger. # this with great vengeance and furious anger.
FAKE_CODE: int = const(-1) FAKE_CODE = const(-1) # type: int
def __call__( def __call__(
self, self,
modified_code: Optional[Key] = None, modified_code=None, # type: Optional[Key]
no_press: Optional[bool] = None, no_press=None, # type: Optional[bool]
no_release: Optional[bool] = None, no_release=None, # type: Optional[bool]
) -> Union[Key, ModifierKey]: ):
# type: (...) -> Union[Key, ModifierKey]
if modified_code is None and no_press is None and no_release is None: if modified_code is None and no_press is None and no_release is None:
return self return self
@ -655,7 +655,8 @@ class ModifierKey(Key):
return new_keycode return new_keycode
def __repr__(self) -> str: def __repr__(self):
# () -> str
return 'ModifierKey(code={}, has_modifiers={})'.format( return 'ModifierKey(code={}, has_modifiers={})'.format(
self.code, self.has_modifiers self.code, self.has_modifiers
) )
@ -665,7 +666,8 @@ class ConsumerKey(Key):
pass pass
def register_key_names(key: Key, names: Tuple[str, ...] = tuple()): # NOQA def register_key_names(key, names=tuple()): # NOQA
# type: (Key, Tuple[str, ...]) -> Key
''' '''
Names are globally unique. If a later key is created with Names are globally unique. If a later key is created with
the same name as an existing entry in `KC`, it will overwrite the same name as an existing entry in `KC`, it will overwrite
@ -686,12 +688,8 @@ def register_key_names(key: Key, names: Tuple[str, ...] = tuple()): # NOQA
return key return key
def make_key( def make_key(code=None, names=tuple(), type=KEY_SIMPLE, **kwargs): # NOQA
code: Optional[int] = None, # type: (Optional[int], Tuple[str, ...], int, **Any) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
names: Tuple[str, ...] = tuple(),
type: int = KEY_SIMPLE,
**kwargs: Any,
) -> KeyReturn: # NOQA
''' '''
Create a new key, aliased by `names` in the KC lookup table. Create a new key, aliased by `names` in the KC lookup table.
@ -733,16 +731,13 @@ def make_key(
return key return key
def make_mod_key( def make_mod_key(code, names, *args, **kwargs):
code: Optional[int], # type: (Optional[int], Tuple[str, ...], *Any, **Any) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
names: Tuple[str, ...],
*args: Any,
**kwargs: Any,
):
return make_key(code, names, *args, **kwargs, type=KEY_MODIFIER) return make_key(code, names, *args, **kwargs, type=KEY_MODIFIER)
def make_shifted_key(target_name, names=tuple()): # NOQA def make_shifted_key(target_name, names=tuple()): # NOQA
# type: (str, Tuple[str, ...]) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
# For... probably a few years, a bug existed here where keys were looked # For... probably a few years, a bug existed here where keys were looked
# up by `KC[...]`, but that's incorrect: an AttrDit exposes a dictionary # up by `KC[...]`, but that's incorrect: an AttrDit exposes a dictionary
# with attributes, but key-based dictionary access with brackets does # with attributes, but key-based dictionary access with brackets does
@ -757,34 +752,28 @@ def make_shifted_key(target_name, names=tuple()): # NOQA
return key return key
def make_consumer_key(*args: Any, **kwargs: Any): def make_consumer_key(*args, **kwargs):
# type: (*Any, **Any) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
return make_key(*args, **kwargs, type=KEY_CONSUMER) return make_key(*args, **kwargs, type=KEY_CONSUMER)
class ArgumentedKey(Protocol):
def __call__(self, *user_args: Any, **user_kwargs: Any) -> Key:
...
class Validator(Protocol):
def __call__(self, *validator_args: Any, **validator_kwargs: Any) -> object:
...
# Argumented keys are implicitly internal, so auto-gen of code # Argumented keys are implicitly internal, so auto-gen of code
# is almost certainly the best plan here # is almost certainly the best plan here
def make_argumented_key( def make_argumented_key(
validator: Validator = lambda *validator_args, **validator_kwargs: object(), validator=lambda *validator_args, **validator_kwargs: object(), # type: object
names: Tuple = tuple(), # NOQA names=tuple(), # type: Tuple[str, ...] # NOQA
*constructor_args: Any, *constructor_args, # type; Any
**constructor_kwargs: Any, **constructor_kwargs, # type: Any
) -> Optional[ArgumentedKey]: ):
global NEXT_AVAILABLE_KEY global NEXT_AVAILABLE_KEY
def _argumented_key(*user_args: Any, **user_kwargs: Any): def _argumented_key(*user_args, **user_kwargs):
# type: (*Any, **Any) -> Union[Key, ModifierKey, ConsumerKey]
global NEXT_AVAILABLE_KEY global NEXT_AVAILABLE_KEY
meta = validator(*user_args, **user_kwargs) meta = validator(
*user_args, **user_kwargs
) # type: Callable[[Any, Any], object]
if meta: if meta:
key = Key( key = Key(

View File

@ -1,77 +1,80 @@
from __future__ import annotations import sys
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union from kmk.consts import KMK_RELEASE, TYPING_PLATFORMS, UnicodeMode
from kmk.consts import KMK_RELEASE, UnicodeMode
from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes
from kmk.keys import KC, Key, KeyAttrDict from kmk.keys import KC, Key, KeyAttrDict
from kmk.kmktime import ticks_ms from kmk.kmktime import ticks_ms
from kmk.matrix import MatrixScanner, intify_coordinate from kmk.matrix import MatrixScanner, intify_coordinate
from kmk.types import TapDanceKeyMeta from kmk.types import TapDanceKeyMeta
if sys.platform in TYPING_PLATFORMS:
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union
class Sandbox: class Sandbox:
matrix_update: Optional[bytearray] = None matrix_update = None # type: Optional[bytearray]
secondary_matrix_update: Optional[bytearray] = None secondary_matrix_update = None # type: Optional[bytearray]
active_layers: Optional[List[int]] = None active_layers = None # type: Optional[List[int]]
class KMKKeyboard: class KMKKeyboard:
##### #####
# User-configurable # User-configurable
debug_enabled: bool = False debug_enabled = False # type: bool
keymap: List[KeyAttrDict] = [] keymap = [] # type: List[KeyAttrDict]
coord_mapping: Optional[List[int]] = None coord_mapping = None # type: Optional[List[int]]
row_pins: Optional[Tuple[Any, ...]] = None row_pins = None # type: Optional[Tuple[Any, ...]]
col_pins: Optional[Tuple[Any, ...]] = None col_pins = None # type: Optional[Tuple[Any, ...]]
diode_orientation: Optional[int] = None diode_orientation = None # type: Optional[int]
matrix: Optional[MatrixScanner] = None matrix = None # type: Optional[MatrixScanner]
matrix_scanner: Type[MatrixScanner] = MatrixScanner matrix_scanner = MatrixScanner # type: Type[MatrixScanner]
uart_buffer: List[Any] = [] uart_buffer = [] # type: List[Any]
unicode_mode: int = UnicodeMode.NOOP unicode_mode = UnicodeMode.NOOP # type: int
tap_time: int = 300 tap_time = 300 # type: int
modules: List[Type[Any]] = [] modules = [] # type: List[Type[Any]]
extensions: List[Type[Any]] = [] extensions = [] # type: List[Type[Any]]
sandbox: Sandbox = Sandbox() sandbox = Sandbox() # type: Sandbox
##### #####
# Internal State # Internal State
keys_pressed: Set[Key] = set() keys_pressed = set() # type: Set[Key]
_coordkeys_pressed: Dict[Any, Any] = {} _coordkeys_pressed = {} # type: Dict[Any, Any]
hid_type: int = HIDModes.USB hid_type = HIDModes.USB # type: int
secondary_hid_type: Optional[int] = None secondary_hid_type = None # type: Optional[int]
_hid_helper: Optional[Union[Type[AbstractHID], Type[BLEHID], Type[USBHID]]] = None _hid_helper = (
hid_pending: bool = False None
state_layer_key: Optional[Key] = None ) # type: Optional[Union[Type[AbstractHID], Type[BLEHID], Type[USBHID]]]
matrix_update: Optional[Union[bytearray, None]] = None hid_pending = False # type: bool
secondary_matrix_update: Optional[Union[bytearray, None]] = None state_layer_key = None # type: Optional[Key]
_matrix_modify: Optional[Any] = None matrix_update = None # type: Optional[Union[bytearray, None]]
state_changed: bool = False secondary_matrix_update = None # type: Optional[Union[bytearray, None]]
_old_timeouts_len: Optional[int] = None _matrix_modify = None # type: Optional[Any]
_new_timeouts_len: Optional[int] = None state_changed = False # type: bool
_trigger_powersave_enable: bool = False _old_timeouts_len = None # type: Optional[int]
_trigger_powersave_disable: bool = False _new_timeouts_len = None # type: Optional[int]
i2c_deinit_count: int = 0 _trigger_powersave_enable = False # type: bool
_trigger_powersave_disable = False # type: bool
i2c_deinit_count = 0 # type: int
# this should almost always be PREpended to, replaces # this should almost always be PREpended to, replaces
# former use of reversed_active_layers which had pointless # former use of reversed_active_layers which had pointless
# overhead (the underlying list was never used anyway) # overhead (the underlying list was never used anyway)
active_layers: List[int] = [0] active_layers = [0] # type: List[int]
_timeouts: Dict[float, Callable[[], Key]] = {} _timeouts = {} # type: Dict[float, Callable[[], Key]]
_tapping: bool = False _tapping = False # type: bool
_tap_dance_counts: Dict[Union[Key, TapDanceKeyMeta], Union[int, None]] = {} _tap_dance_counts = {} # type: Dict[Union[Key, TapDanceKeyMeta], Union[int, None]]
_tap_side_effects: Dict[Union[Key, TapDanceKeyMeta], Union[Key, None]] = {} _tap_side_effects = {} # type: Dict[Union[Key, TapDanceKeyMeta], Union[int, None]]
# on some M4 setups (such as klardotsh/klarank_feather_m4, CircuitPython # on some M4 setups (such as klardotsh/klarank_feather_m4, CircuitPython
# 6.0rc1) this runs out of RAM every cycle and takes down the board. no # 6.0rc1) this runs out of RAM every cycle and takes down the board. no
# real known fix yet other than turning off debug, but M4s have always been # real known fix yet other than turning off debug, but M4s have always been
# tight on RAM so.... # tight on RAM so....
def __repr__(self) -> str: def __repr__(self): # type: () -> str
return ( return (
'KMKKeyboard(' 'KMKKeyboard('
'debug_enabled={} ' 'debug_enabled={} '
@ -107,22 +110,26 @@ class KMKKeyboard:
self._tap_side_effects, self._tap_side_effects,
) )
def _print_debug_cycle(self, init: bool = False) -> None: def _print_debug_cycle(self, init=False):
# type: (bool) -> None
if self.debug_enabled: if self.debug_enabled:
if init: if init:
print('KMKInit(release={})'.format(KMK_RELEASE)) print('KMKInit(release={})'.format(KMK_RELEASE))
print(self) print(self)
def _send_hid(self) -> None: def _send_hid(self):
# type: () -> None
self._hid_helper.create_report(self.keys_pressed).send() self._hid_helper.create_report(self.keys_pressed).send()
self.hid_pending = False self.hid_pending = False
def _handle_matrix_report(self, update: bytearray = None) -> None: def _handle_matrix_report(self, update=None):
# type: (Optional[bytearray]) -> None
if update is not None: if update is not None:
self._on_matrix_changed(update[0], update[1], update[2]) self._on_matrix_changed(update[0], update[1], update[2])
self.state_changed = True self.state_changed = True
def _find_key_in_map(self, int_coord: int, row: int, col: int) -> Union[Key, None]: def _find_key_in_map(self, int_coord, row, col):
# type: (int, int, int) -> Optional[Key]
self.state_layer_key = None self.state_layer_key = None
try: try:
idx = self.coord_mapping.index(int_coord) idx = self.coord_mapping.index(int_coord)
@ -147,7 +154,8 @@ class KMKKeyboard:
return self.state_layer_key return self.state_layer_key
def _on_matrix_changed(self, row: int, col: int, is_pressed: int) -> KMKKeyboard: def _on_matrix_changed(self, row, col, is_pressed):
# type: (int, int, int) -> KMKKeyboard
if self.debug_enabled: if self.debug_enabled:
print('MatrixChange(col={} row={} pressed={})'.format(col, row, is_pressed)) print('MatrixChange(col={} row={} pressed={})'.format(col, row, is_pressed))
@ -162,11 +170,12 @@ class KMKKeyboard:
def process_key( def process_key(
self, self,
key: Union[Key, TapDanceKeyMeta], key, # type: Union[Key, TapDanceKeyMeta]
is_pressed: int, is_pressed, # type: int
coord_int: Optional[int] = None, coord_int=None, # type: Optional[int]
coord_raw: Tuple[int, int] = None, coord_raw=None, # type: Optional[Tuple[int, int]]
) -> KMKKeyboard: ):
# (...) -> KMKKeyboard
if self._tapping and not isinstance(key.meta, TapDanceKeyMeta): if self._tapping and not isinstance(key.meta, TapDanceKeyMeta):
self._process_tap_dance(key, is_pressed) self._process_tap_dance(key, is_pressed)
else: else:
@ -177,24 +186,26 @@ class KMKKeyboard:
return self return self
def remove_key(self, keycode: Key) -> KMKKeyboard: def remove_key(self, keycode):
# type: (Key) -> KMKKeyboard
self.keys_pressed.discard(keycode) self.keys_pressed.discard(keycode)
return self.process_key(keycode, False) return self.process_key(keycode, False)
def add_key(self, keycode: Key) -> KMKKeyboard: def add_key(self, keycode):
# type: (Key) -> KMKKeyboard
self.keys_pressed.add(keycode) self.keys_pressed.add(keycode)
return self.process_key(keycode, True) return self.process_key(keycode, True)
def tap_key(self, keycode: Key) -> KMKKeyboard: def tap_key(self, keycode):
# type: (Key) -> KMKKeyboard
self.add_key(keycode) self.add_key(keycode)
# On the next cycle, we'll remove the key. # On the next cycle, we'll remove the key.
self.set_timeout(False, lambda: self.remove_key(keycode)) self.set_timeout(False, lambda: self.remove_key(keycode))
return self return self
def _process_tap_dance( def _process_tap_dance(self, changed_key, is_pressed):
self, changed_key: Union[Key, TapDanceKeyMeta], is_pressed: int # type: (Union[Key, TapDanceKeyMeta], int) -> KMKKeyboard
) -> KMKKeyboard:
if is_pressed: if is_pressed:
if not isinstance(changed_key.meta, TapDanceKeyMeta): if not isinstance(changed_key.meta, TapDanceKeyMeta):
# If we get here, changed_key is not a TapDanceKey and thus # If we get here, changed_key is not a TapDanceKey and thus
@ -231,7 +242,8 @@ class KMKKeyboard:
return self return self
def _end_tap_dance(self, td_key: Union[Key, TapDanceKeyMeta]) -> KMKKeyboard: def _end_tap_dance(self, td_key):
# type: (Union[Key, TapDanceKeyMeta]) -> KMKKeyboard
v = self._tap_dance_counts[td_key] - 1 v = self._tap_dance_counts[td_key] - 1
if v >= 0: if v >= 0:
@ -252,12 +264,14 @@ class KMKKeyboard:
return self return self
def _cleanup_tap_dance(self, td_key: Union[Key, TapDanceKeyMeta]) -> KMKKeyboard: def _cleanup_tap_dance(self, td_key):
# type: (Union[Key, TapDanceKeyMeta]) -> KMKKeyboard
self._tap_dance_counts[td_key] = 0 self._tap_dance_counts[td_key] = 0
self._tapping = any(count > 0 for count in self._tap_dance_counts.values()) self._tapping = any(count > 0 for count in self._tap_dance_counts.values())
return self return self
def set_timeout(self, after_ticks: float, callback: Callable[[], Key]) -> float: def set_timeout(self, after_ticks, callback):
# type: (float, Callable[[], Key]) -> float
if after_ticks is False: if after_ticks is False:
# We allow passing False as an implicit "run this on the next process timeouts cycle" # We allow passing False as an implicit "run this on the next process timeouts cycle"
timeout_key = ticks_ms() timeout_key = ticks_ms()
@ -270,11 +284,13 @@ class KMKKeyboard:
self._timeouts[timeout_key] = callback self._timeouts[timeout_key] = callback
return timeout_key return timeout_key
def _cancel_timeout(self, timeout_key: float) -> None: def _cancel_timeout(self, timeout_key):
# type: (float) -> None
if timeout_key in self._timeouts: if timeout_key in self._timeouts:
del self._timeouts[timeout_key] del self._timeouts[timeout_key]
def _process_timeouts(self) -> KMKKeyboard: def _process_timeouts(self):
# type: () -> KMKKeyboard
if not self._timeouts: if not self._timeouts:
return self return self
@ -291,7 +307,8 @@ class KMKKeyboard:
return self return self
def _init_sanity_check(self) -> KMKKeyboard: def _init_sanity_check(self):
# type: () -> KMKKeyboard
''' '''
Ensure the provided configuration is *probably* bootable Ensure the provided configuration is *probably* bootable
''' '''
@ -305,7 +322,8 @@ class KMKKeyboard:
return self return self
def _init_coord_mapping(self) -> None: def _init_coord_mapping(self):
# () -> None
''' '''
Attempt to sanely guess a coord_mapping if one is not provided. No-op Attempt to sanely guess a coord_mapping if one is not provided. No-op
if `kmk.extensions.split.Split` is used, it provides equivalent if `kmk.extensions.split.Split` is used, it provides equivalent
@ -327,7 +345,8 @@ class KMKKeyboard:
for cidx in range(cols_to_calc): for cidx in range(cols_to_calc):
self.coord_mapping.append(intify_coordinate(ridx, cidx)) self.coord_mapping.append(intify_coordinate(ridx, cidx))
def _init_hid(self) -> None: def _init_hid(self):
# type: () -> None
if self.hid_type == HIDModes.NOOP: if self.hid_type == HIDModes.NOOP:
self._hid_helper = AbstractHID self._hid_helper = AbstractHID
elif self.hid_type == HIDModes.USB: elif self.hid_type == HIDModes.USB:
@ -338,7 +357,8 @@ class KMKKeyboard:
self._hid_helper = AbstractHID self._hid_helper = AbstractHID
self._hid_helper = self._hid_helper() self._hid_helper = self._hid_helper()
def _init_matrix(self) -> KMKKeyboard: def _init_matrix(self):
# type: () -> KMKKeyboard
self.matrix = MatrixScanner( self.matrix = MatrixScanner(
cols=self.col_pins, cols=self.col_pins,
rows=self.row_pins, rows=self.row_pins,
@ -348,7 +368,8 @@ class KMKKeyboard:
return self return self
def before_matrix_scan(self) -> None: def before_matrix_scan(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.before_matrix_scan(self) module.before_matrix_scan(self)
@ -363,7 +384,8 @@ class KMKKeyboard:
if self.debug_enabled: if self.debug_enabled:
print('Failed to run pre matrix function in extension: ', err, ext) print('Failed to run pre matrix function in extension: ', err, ext)
def after_matrix_scan(self) -> None: def after_matrix_scan(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.after_matrix_scan(self) module.after_matrix_scan(self)
@ -378,7 +400,8 @@ class KMKKeyboard:
if self.debug_enabled: if self.debug_enabled:
print('Failed to run post matrix function in extension: ', err, ext) print('Failed to run post matrix function in extension: ', err, ext)
def before_hid_send(self) -> None: def before_hid_send(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.before_hid_send(self) module.before_hid_send(self)
@ -393,7 +416,8 @@ class KMKKeyboard:
if self.debug_enabled: if self.debug_enabled:
print('Failed to run pre hid function in extension: ', err, ext) print('Failed to run pre hid function in extension: ', err, ext)
def after_hid_send(self) -> None: def after_hid_send(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.after_hid_send(self) module.after_hid_send(self)
@ -408,7 +432,8 @@ class KMKKeyboard:
if self.debug_enabled: if self.debug_enabled:
print('Failed to run post hid function in extension: ', err, ext) print('Failed to run post hid function in extension: ', err, ext)
def powersave_enable(self) -> None: def powersave_enable(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.on_powersave_enable(self) module.on_powersave_enable(self)
@ -423,7 +448,8 @@ class KMKKeyboard:
if self.debug_enabled: if self.debug_enabled:
print('Failed to run post hid function in extension: ', err, ext) print('Failed to run post hid function in extension: ', err, ext)
def powersave_disable(self) -> None: def powersave_disable(self):
# type: () -> None
for module in self.modules: for module in self.modules:
try: try:
module.on_powersave_disable(self) module.on_powersave_disable(self)
@ -439,10 +465,11 @@ class KMKKeyboard:
def go( def go(
self, self,
hid_type: int = HIDModes.USB, hid_type=HIDModes.USB, # type: int
secondary_hid_type: Optional[int] = None, secondary_hid_type=None, # type: Optional[int]
**kwargs: Dict[Any, Any], **kwargs, # type: Dict[Any, Any]
) -> None: ):
# (...) -> None
self.hid_type = hid_type self.hid_type = hid_type
self.secondary_hid_type = secondary_hid_type self.secondary_hid_type = secondary_hid_type

View File

@ -1,23 +1,28 @@
import time import time
def sleep_ms(ms: float) -> None: def sleep_ms(ms):
# type: (float) -> None
return time.sleep(ms / 1000) return time.sleep(ms / 1000)
def ticks_ms() -> float: def ticks_ms():
# type: () -> float
'''Has .25s granularity, but is cheap''' '''Has .25s granularity, but is cheap'''
return time.monotonic() * 1000 return time.monotonic() * 1000
def ticks_diff(new: float, old: float) -> float: def ticks_diff(new, old):
# type: (float, float) -> float
return new - old return new - old
def accurate_ticks() -> int: def accurate_ticks():
# type: () -> int
'''Is more expensive, but good for time critical things''' '''Is more expensive, but good for time critical things'''
return time.monotonic_ns() return time.monotonic_ns()
def accurate_ticks_diff(new: float, old: float, ms: float) -> bool: def accurate_ticks_diff(new, old, ms):
# type: (float, float, float) -> bool
return bool(new - old < ms * 1000000) return bool(new - old < ms * 1000000)

View File

@ -1,6 +1,12 @@
from typing import List, Optional, Tuple import sys
from kmk.keys import Key from kmk.consts import TYPING_PLATFORMS
if sys.platform in TYPING_PLATFORMS:
from typing import List, Optional, Tuple, Union
# Avoid cyclical imports
from kmk.keys import ConsumerKey, Key, ModifierKey
class AttrDict(dict): class AttrDict(dict):
@ -12,39 +18,44 @@ class AttrDict(dict):
This is read-only on purpose. This is read-only on purpose.
''' '''
def __getattr__(self, key: str) -> str: def __getattr__(self, key):
# type: (str) -> Optional[Union[Key, ModifierKey, ConsumerKey]]
return self[key] return self[key]
class LayerKeyMeta: class LayerKeyMeta:
def __init__(self, layer: int, kc: Optional[Key] = None) -> None: def __init__(self, layer, kc=None):
self.layer: int = layer # type: (int, Optional[Key]) -> None
self.kc: Optional[Key] = kc self.layer = layer # type: int
self.kc = kc # type: Optional[Key]
class ModTapKeyMeta: class ModTapKeyMeta:
def __init__( def __init__(self, kc=None, mods=None):
self, kc: Optional[Key] = None, mods: Optional[List[Key]] = None # type: (Optional[Key], Optional[List[Key]]) -> None
) -> None: self.mods = mods # type: Optional[List[Key]]
self.mods: Optional[List[Key]] = mods self.kc = kc # type: Optional[Key]
self.kc: Optional[Key] = kc
class KeySequenceMeta: class KeySequenceMeta:
def __init__(self, seq: List[Key]): def __init__(self, seq):
self.seq: List[Key] = seq # type: (List[Key]) -> None
self.seq = seq # type: List[Key]
class KeySeqSleepMeta: class KeySeqSleepMeta:
def __init__(self, ms: float): def __init__(self, ms):
self.ms: float = ms # type: (float) -> None
self.ms = ms # type: float
class UnicodeModeKeyMeta: class UnicodeModeKeyMeta:
def __init__(self, mode: int): def __init__(self, mode):
self.mode: int = mode # type: (int) -> None
self.mode = mode # type: int
class TapDanceKeyMeta: class TapDanceKeyMeta:
def __init__(self, codes: Tuple[Key, ...]): def __init__(self, codes):
self.codes: Tuple[Key, ...] = codes # type: (Tuple[Key, ...]) -> None
self.codes = codes # type: Tuple[Key, ...]

View File

@ -24,18 +24,25 @@ exclude = '''
''' '''
[tool.pyright] [tool.pyright]
strict = ["kmk"]
typeCheckingMode = "strict"
include = ["kmk"] include = ["kmk"]
exclude = [ exclude = [
"hardware", "hardware",
".venv", ".venv",
"user_keymaps", "user_keymaps",
"boards" "boards",
".git"
] ]
venvPath = ".venv"
# stops constant reporting of missing board module etc.
reportMissingModuleSource = false reportMissingModuleSource = false
# reports missing typestubs allowing for a code action to # reports missing typestubs allowing for a code action to
# create new library typestubs # create new library typestubs
reportMissingTypeStubs = true reportMissingTypeStubs = true
pythonVersion = "3.6"
[tool.mypy] [tool.mypy]
exclude = "boards/|user_keymaps/" exclude = "boards/|user_keymaps/"
ignore_missing_imports = true ignore_missing_imports = true
python_version = "3.6"