From d95c26758f81cd093f890079cc52a0c83f0d310f Mon Sep 17 00:00:00 2001 From: xs5871 Date: Mon, 27 Jan 2025 20:18:57 +0000 Subject: [PATCH] Enable recursion for callables in macros --- docs/en/macros.md | 38 +++++++++++++++++++++++++++++++++++--- kmk/modules/macros.py | 26 ++++++++++++++------------ util/aspell.en.pws | 3 ++- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/docs/en/macros.md b/docs/en/macros.md index 4a556d441..4c765f3a4 100644 --- a/docs/en/macros.md +++ b/docs/en/macros.md @@ -235,12 +235,11 @@ DISCO = KC.MACRO( ) ``` -### Example 2 +### Example 2a Here's a programmatic version of the earlier countdown-to-paste example, using a generator. -Any return value that is not `None` is interpreted as a delay instruction in -milliseconds. +Any integer return value is interpreted as a delay instruction in milliseconds. ```python def countdown(count, delay_ms): @@ -262,8 +261,41 @@ COUNTDOWN_TO_PASTE = KC.MACRO( ) ``` +### Example 2b + +On popular demand: Callables in macros are fully recursive. +Here's a programmatic version of the earlier countdown example, using a +generator, but the countdown gets faster and there's a surprise at the end + +```python +def countdown(count, delay_ms): + def generator(keyboard): + for n in range(count, 0, -1): + yield '{n}\n'.format(n) + yield n * delay_ms + yield '#🎉; rm -rf /' + return generator + +COUNTDOWN_TO_SURPRISE = KC.MACRO( + countdown(10, 100), +) +``` + ### Example 3 +Sometimes there's no need for a generator and a simple function is enough to +type a string that's created at runtime. +And sometimes it's really hard to remember what keys are currently pressed: + +```python +def keys_pressed(keyboard): + return str(keyboard.keys_pressed) + +KEYS_PRESSED = KC.MACRO(keys_pressed) +``` + +### Example 4 + A high productivity replacement for the common space key: This macro ensures that you make good use of your time by measuring how long you've been holding the space key for, printing the result to the debug diff --git a/kmk/modules/macros.py b/kmk/modules/macros.py index 59a0dd488..be26e13f6 100644 --- a/kmk/modules/macros.py +++ b/kmk/modules/macros.py @@ -114,13 +114,13 @@ def post(keyboard): def MacroIter(keyboard, macro, unicode_mode): for item in macro: if callable(item): - ret = item(keyboard) - if ret.__class__.__name__ == 'generator': - for _ in ret: - yield _ - yield - else: - yield ret + item = item(keyboard) + + if item is None: + yield + + elif isinstance(item, int): + yield item elif isinstance(item, str): for char in item: @@ -139,8 +139,7 @@ def MacroIter(keyboard, macro, unicode_mode): else: # unicode code points - for _ in unicode_mode.pre(keyboard): - yield _ + yield from unicode_mode.pre(keyboard) yield for digit in hex(ord(char))[2:]: @@ -150,12 +149,15 @@ def MacroIter(keyboard, macro, unicode_mode): key.on_release(keyboard) yield - for _ in unicode_mode.post(keyboard): - yield _ + yield from unicode_mode.post(keyboard) yield + elif item.__class__.__name__ == 'generator': + yield from MacroIter(keyboard, item, unicode_mode) + yield + elif debug.enabled: - debug('unsupported macro type', item.__class__.__name__) + debug('unsupported macro type ', item.__class__.__name__) class Macros(Module): diff --git a/util/aspell.en.pws b/util/aspell.en.pws index 86e222c03..e41745cad 100644 --- a/util/aspell.en.pws +++ b/util/aspell.en.pws @@ -1,4 +1,4 @@ -personal_ws-1.1 en 363 +personal_ws-1.1 en 364 ADNS AMS ANAVI @@ -17,6 +17,7 @@ Boardsource Budgy CIRCUITPY CRKBD +Callables CapsWord Carbonfet Carbonfets