feat(extensions): most of the extensions implementation, by kdb424

This commit is contained in:
Kyle Brown
2020-10-21 12:19:42 -07:00
committed by Josh Klar
parent 9821f7bcc3
commit e72d2b8c34
140 changed files with 3860 additions and 2312 deletions

View File

@@ -8,35 +8,44 @@ class Extension:
def enable(self, keyboard):
self._enabled = True
self.on_runtime_enable(self, keyboard)
self.on_runtime_enable(keyboard)
def disable(self, keyboard):
self._enabled = False
self.on_runtime_disable(self, keyboard)
self.on_runtime_disable(keyboard)
# The below methods should be implemented by subclasses
def on_runtime_enable(self, keyboard):
pass
raise NotImplementedError
def on_runtime_disable(self, keyboard):
pass
raise NotImplementedError
def during_bootup(self, keyboard):
pass
raise NotImplementedError
def before_matrix_scan(self, keyboard):
'''
Return value will be injected as an extra matrix update
'''
pass
raise NotImplementedError
def after_matrix_scan(self, keyboard, matrix_update):
pass
def after_matrix_scan(self, keyboard):
'''
Return value will be replace matrix update if supplied
'''
raise NotImplementedError
def before_hid_send(self, keyboard):
pass
raise NotImplementedError
def after_hid_send(self, keyboard):
pass
raise NotImplementedError
def on_powersave_enable(self, keyboard):
raise NotImplementedError
def on_powersave_disable(self, keyboard):
raise NotImplementedError

View File

@@ -0,0 +1,59 @@
'''Adds international keys'''
from kmk.extensions import Extension
from kmk.keys import make_key
class International(Extension):
'''Adds international keys'''
def __init__(self):
# International
make_key(code=50, names=('NONUS_HASH', 'NUHS'))
make_key(code=100, names=('NONUS_BSLASH', 'NUBS'))
make_key(code=101, names=('APP', 'APPLICATION', 'SEL', 'WINMENU'))
make_key(code=135, names=('INT1', 'RO'))
make_key(code=136, names=('INT2', 'KANA'))
make_key(code=137, names=('INT3', 'JYEN'))
make_key(code=138, names=('INT4', 'HENK'))
make_key(code=139, names=('INT5', 'MHEN'))
make_key(code=140, names=('INT6',))
make_key(code=141, names=('INT7',))
make_key(code=142, names=('INT8',))
make_key(code=143, names=('INT9',))
make_key(code=144, names=('LANG1', 'HAEN'))
make_key(code=145, names=('LANG2', 'HAEJ'))
make_key(code=146, names=('LANG3',))
make_key(code=147, names=('LANG4',))
make_key(code=148, names=('LANG5',))
make_key(code=149, names=('LANG6',))
make_key(code=150, names=('LANG7',))
make_key(code=151, names=('LANG8',))
make_key(code=152, names=('LANG9',))
def on_runtime_enable(self, sandbox):
return
def on_runtime_disable(self, sandbox):
return
def during_bootup(self, sandbox):
return
def before_matrix_scan(self, sandbox):
return
def after_matrix_scan(self, sandbox):
return
def before_hid_send(self, sandbox):
return
def after_hid_send(self, sandbox):
return
def on_powersave_enable(self, sandbox):
return
def on_powersave_disable(self, sandbox):
return

View File

@@ -1,111 +0,0 @@
import gc
from kmk.extensions import Extension, InvalidExtensionEnvironment
from kmk.handlers.stock import passthrough as handler_passthrough
from kmk.keys import KC, make_key
class LeaderMode:
TIMEOUT = 0
TIMEOUT_ACTIVE = 1
ENTER = 2
ENTER_ACTIVE = 3
class Leader(Extension):
def __init__(self, mode=LeaderMode.TIMEOUT, timeout=1000, sequences=None):
if sequences is None:
raise InvalidExtensionEnvironment(
'sequences must be a dictionary, not None'
)
self._mode = mode
self._timeout = timeout
self._sequences = self._compile_sequences(sequences)
self._leader_pending = None
self._assembly_last_len = 0
self._sequence_assembly = []
make_key(
names=('LEADER', 'LEAD'),
on_press=self._key_leader_pressed,
on_release=handler_passthrough,
)
gc.collect()
def after_matrix_scan(self, keyboard_state, *args):
if self._mode % 2 == 1:
keys_pressed = keyboard_state._keys_pressed
if self._assembly_last_len and self._sequence_assembly:
history_set = set(self._sequence_assembly)
keys_pressed = keys_pressed - history_set
self._assembly_last_len = len(keyboard_state._keys_pressed)
for key in keys_pressed:
if self._mode == LeaderMode.ENTER_ACTIVE and key == KC.ENT:
self._handle_leader_sequence(keyboard_state)
break
elif key == KC.ESC or key == KC.GESC:
# Clean self and turn leader mode off.
self._exit_leader_mode(keyboard_state)
break
elif key == KC.LEAD:
break
else:
# Add key if not needing to escape
# This needs replaced later with a proper debounce
self._sequence_assembly.append(key)
keyboard_state._hid_pending = False
def _compile_sequences(self, sequences):
gc.collect()
for k, v in sequences.items():
if not isinstance(k, tuple):
new_key = tuple(KC[c] for c in k)
sequences[new_key] = v
for k, v in sequences.items():
if not isinstance(k, tuple):
del sequences[k]
gc.collect()
return sequences
def _handle_leader_sequence(self, keyboard_state):
lmh = tuple(self._sequence_assembly)
# Will get caught in infinite processing loops if we don't
# exit leader mode before processing the target key
self._exit_leader_mode(keyboard_state)
if lmh in self._sequences:
# Stack depth exceeded if try to use add_key here with a unicode sequence
keyboard_state._process_key(self._sequences[lmh], True)
keyboard_state._set_timeout(
False, lambda: keyboard_state._remove_key(self._sequences[lmh])
)
def _exit_leader_mode(self, keyboard_state):
self._sequence_assembly.clear()
self._mode -= 1
self._assembly_last_len = 0
keyboard_state._keys_pressed.clear()
def _key_leader_pressed(self, key, keyboard_state, *args, **kwargs):
if self._mode % 2 == 0:
keyboard_state._keys_pressed.discard(key)
# All leader modes are one number higher when activating
self._mode += 1
if self._mode == LeaderMode.TIMEOUT_ACTIVE:
keyboard_state._set_timeout(
self._timeout, lambda: self._handle_leader_sequence(keyboard_state)
)

218
kmk/extensions/led.py Normal file
View File

@@ -0,0 +1,218 @@
import pulseio
from math import e, exp, pi, sin
from kmk.extensions import Extension, InvalidExtensionEnvironment
from kmk.keys import make_key
class AnimationModes:
OFF = 0
STATIC = 1
STATIC_STANDBY = 2
BREATHING = 3
USER = 4
class LED(Extension):
def __init__(
self,
led_pin,
brightness_step=5,
brightness_limit=100,
breathe_center=1.5,
animation_mode=AnimationModes.STATIC,
animation_speed=1,
user_animation=None,
val=100,
):
try:
self._led = pulseio.PWMOut(led_pin)
except Exception as e:
print(e)
raise InvalidExtensionEnvironment(
'Unable to create pulseio.PWMOut() instance with provided led_pin'
)
self._brightness = 0
self._pos = 0
self._effect_init = False
self._enabled = True
self.brightness_step = brightness_step
self.brightness_limit = brightness_limit
self.animation_mode = animation_mode
self.animation_speed = animation_speed
self.breathe_center = breathe_center
self.val = val
if user_animation is not None:
self.user_animation = user_animation
make_key(names=('LED_TOG',), on_press=self._key_led_tog)
make_key(names=('LED_INC',), on_press=self._key_led_inc)
make_key(names=('LED_DEC',), on_press=self._key_led_dec)
make_key(names=('LED_ANI',), on_press=self._key_led_ani)
make_key(names=('LED_AND',), on_press=self._key_led_and)
make_key(
names=('LED_MODE_PLAIN', 'LED_M_P'), on_press=self._key_led_mode_static
)
make_key(
names=('LED_MODE_BREATHE', 'LED_M_B'), on_press=self._key_led_mode_breathe
)
def __repr__(self):
return 'LED({})'.format(self._to_dict())
def _to_dict(self):
return {
'_brightness': self._brightness,
'_pos': self._pos,
'brightness_step': self.brightness_step,
'brightness_limit': self.brightness_limit,
'animation_mode': self.animation_mode,
'animation_speed': self.animation_speed,
'breathe_center': self.breathe_center,
'val': self.val,
}
def on_runtime_enable(self, sandbox):
return
def on_runtime_disable(self, sandbox):
return
def during_bootup(self, sandbox):
return
def before_matrix_scan(self, sandbox):
return
def after_matrix_scan(self, sandbox):
return
def before_hid_send(self, sandbox):
return
def after_hid_send(self, sandbox):
if self._enabled and self.animation_mode:
self.animate()
return
def on_powersave_enable(self, sandbox):
return
def on_powersave_disable(self, sandbox):
return
def _init_effect(self):
self._pos = 0
self._effect_init = False
return self
def set_brightness(self, percent):
self._led.duty_cycle = int(percent / 100 * 65535)
def increase_brightness(self, step=None):
if not step:
self._brightness += self.brightness_step
else:
self._brightness += step
if self._brightness > 100:
self._brightness = 100
self.set_brightness(self._brightness)
def decrease_brightness(self, step=None):
if not step:
self._brightness -= self.brightness_step
else:
self._brightness -= step
if self._brightness < 0:
self._brightness = 0
self.set_brightness(self._brightness)
def off(self):
self.set_brightness(0)
def increase_ani(self):
'''
Increases animation speed by 1 amount stopping at 10
:param step:
'''
if (self.animation_speed + 1) >= 10:
self.animation_speed = 10
else:
self.val += 1
def decrease_ani(self):
'''
Decreases animation speed by 1 amount stopping at 0
:param step:
'''
if (self.val - 1) <= 0:
self.val = 0
else:
self.val -= 1
def effect_breathing(self):
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
sined = sin((self._pos / 255.0) * pi)
multip_1 = exp(sined) - self.breathe_center / e
multip_2 = self.brightness_limit / (e - 1 / e)
self._brightness = int(multip_1 * multip_2)
self._pos = (self._pos + self.animation_speed) % 256
self.set_brightness(self._brightness)
def effect_static(self):
self.set_brightness(self._brightness)
# Set animation mode to none to prevent cycles from being wasted
self.animation_mode = None
def animate(self):
'''
Activates a "step" in the animation based on the active mode
:return: Returns the new state in animation
'''
if self._effect_init:
self._init_effect()
if self._enabled:
if self.animation_mode == AnimationModes.BREATHING:
return self.effect_breathing()
elif self.animation_mode == AnimationModes.STATIC:
return self.effect_static()
elif self.animation_mode == AnimationModes.USER:
return self.user_animation(self)
else:
self.off()
def _key_led_tog(self, *args, **kwargs):
if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC
self._enabled = not self._enabled
def _key_led_inc(self, *args, **kwargs):
self.increase_brightness()
def _key_led_dec(self, *args, **kwargs):
self.decrease_brightness()
def _key_led_ani(self, *args, **kwargs):
self.increase_ani()
def _key_led_and(self, *args, **kwargs):
self.decrease_ani()
def _key_led_mode_static(self, *args, **kwargs):
self._effect_init = True
self.animation_mode = AnimationModes.STATIC
def _key_led_mode_breathe(self, *args, **kwargs):
self._effect_init = True
self.animation_mode = AnimationModes.BREATHING

View File

@@ -0,0 +1,55 @@
from kmk.extensions import Extension
from kmk.keys import make_consumer_key
class MediaKeys(Extension):
def __init__(self):
# Consumer ("media") keys. Most known keys aren't supported here. A much
# longer list used to exist in this file, but the codes were almost certainly
# incorrect, conflicting with each other, or otherwise 'weird'. We'll add them
# back in piecemeal as needed. PRs welcome.
#
# A super useful reference for these is http://www.freebsddiary.org/APC/usb_hid_usages.php
# Note that currently we only have the PC codes. Recent MacOS versions seem to
# support PC media keys, so I don't know how much value we would get out of
# adding the old Apple-specific consumer codes, but again, PRs welcome if the
# lack of them impacts you.
make_consumer_key(code=226, names=('AUDIO_MUTE', 'MUTE')) # 0xE2
make_consumer_key(code=233, names=('AUDIO_VOL_UP', 'VOLU')) # 0xE9
make_consumer_key(code=234, names=('AUDIO_VOL_DOWN', 'VOLD')) # 0xEA
make_consumer_key(code=181, names=('MEDIA_NEXT_TRACK', 'MNXT')) # 0xB5
make_consumer_key(code=182, names=('MEDIA_PREV_TRACK', 'MPRV')) # 0xB6
make_consumer_key(code=183, names=('MEDIA_STOP', 'MSTP')) # 0xB7
make_consumer_key(
code=205, names=('MEDIA_PLAY_PAUSE', 'MPLY')
) # 0xCD (this may not be right)
make_consumer_key(code=184, names=('MEDIA_EJECT', 'EJCT')) # 0xB8
make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3
make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4
def on_runtime_enable(self, sandbox):
return
def on_runtime_disable(self, sandbox):
return
def during_bootup(self, sandbox):
return
def before_matrix_scan(self, sandbox):
return
def after_matrix_scan(self, sandbox):
return
def before_hid_send(self, sandbox):
return
def after_hid_send(self, sandbox):
return
def on_powersave_enable(self, sandbox):
return
def on_powersave_disable(self, sandbox):
return

601
kmk/extensions/rgb.py Normal file
View File

@@ -0,0 +1,601 @@
import neopixel
import time
from math import e, exp, pi, sin
from kmk.extensions import Extension
from kmk.handlers.stock import passthrough as handler_passthrough
from kmk.keys import make_key
rgb_config = {}
class AnimationModes:
OFF = 0
STATIC = 1
STATIC_STANDBY = 2
BREATHING = 3
RAINBOW = 4
BREATHING_RAINBOW = 5
KNIGHT = 6
SWIRL = 7
USER = 8
class RGB(Extension):
pos = 0
time = int(time.monotonic() * 10)
intervals = (30, 20, 10, 5)
def __init__(
self,
pixel_pin,
num_pixels=0,
val_limit=100,
hue_default=0,
sat_default=100,
rgb_order=(1, 0, 2), # GRB WS2812
val_default=100,
hue_step=5,
sat_step=5,
val_step=5,
animation_speed=1,
breathe_center=1, # 1.0-2.7
knight_effect_length=3,
animation_mode=AnimationModes.STATIC,
effect_init=False,
reverse_animation=False,
user_animation=None,
disable_auto_write=False,
loopcounter=0,
):
self.neopixel = neopixel.NeoPixel(
pixel_pin,
num_pixels,
pixel_order=rgb_order,
auto_write=not disable_auto_write,
)
self.rgbw = bool(len(rgb_order) == 4)
self.num_pixels = num_pixels
self.hue_step = hue_step
self.sat_step = sat_step
self.val_step = val_step
self.hue = hue_default
self.hue_default = hue_default
self.sat = sat_default
self.sat_default = sat_default
self.val = val_default
self.val_default = val_default
self.breathe_center = breathe_center
self.knight_effect_length = knight_effect_length
self.val_limit = val_limit
self.animation_mode = animation_mode
self.animation_speed = animation_speed
self.effect_init = effect_init
self.reverse_animation = reverse_animation
self.user_animation = user_animation
self.disable_auto_write = disable_auto_write
self.loopcounter = loopcounter
make_key(
names=('RGB_TOG',), on_press=self._rgb_tog, on_release=handler_passthrough
)
make_key(
names=('RGB_HUI',), on_press=self._rgb_hui, on_release=handler_passthrough
)
make_key(
names=('RGB_HUD',), on_press=self._rgb_hud, on_release=handler_passthrough
)
make_key(
names=('RGB_SAI',), on_press=self._rgb_sai, on_release=handler_passthrough
)
make_key(
names=('RGB_SAD',), on_press=self._rgb_sad, on_release=handler_passthrough
)
make_key(
names=('RGB_VAI',), on_press=self._rgb_vai, on_release=handler_passthrough
)
make_key(
names=('RGB_VAD',), on_press=self._rgb_vad, on_release=handler_passthrough
)
make_key(
names=('RGB_ANI',), on_press=self._rgb_ani, on_release=handler_passthrough
)
make_key(
names=('RGB_AND',), on_press=self._rgb_and, on_release=handler_passthrough
)
make_key(
names=('RGB_MODE_PLAIN', 'RGB_M_P'),
on_press=self._rgb_mode_static,
on_release=handler_passthrough,
)
make_key(
names=('RGB_MODE_BREATHE', 'RGB_M_B'),
on_press=self._rgb_mode_breathe,
on_release=handler_passthrough,
)
make_key(
names=('RGB_MODE_RAINBOW', 'RGB_M_R'),
on_press=self._rgb_mode_rainbow,
on_release=handler_passthrough,
)
make_key(
names=('RGB_MODE_BREATHE_RAINBOW', 'RGB_M_BR'),
on_press=self._rgb_mode_breathe_rainbow,
on_release=handler_passthrough,
)
make_key(
names=('RGB_MODE_SWIRL', 'RGB_M_S'),
on_press=self._rgb_mode_swirl,
on_release=handler_passthrough,
)
make_key(
names=('RGB_MODE_KNIGHT', 'RGB_M_K'),
on_press=self._rgb_mode_knight,
on_release=handler_passthrough,
)
make_key(
names=('RGB_RESET', 'RGB_RST'),
on_press=self._rgb_reset,
on_release=handler_passthrough,
)
def on_runtime_enable(self, sandbox):
return
def on_runtime_disable(self, sandbox):
return
def during_bootup(self, sandbox):
return
def before_matrix_scan(self, sandbox):
return
def after_matrix_scan(self, sandbox):
return
def before_hid_send(self, sandbox):
return
def after_hid_send(self, sandbox):
self.animate()
def on_powersave_enable(self, sandbox):
return
def on_powersave_disable(self, sandbox):
self._do_update()
@staticmethod
def time_ms():
return int(time.monotonic() * 1000)
def hsv_to_rgb(self, hue, sat, val):
'''
Converts HSV values, and returns a tuple of RGB values
:param hue:
:param sat:
:param val:
:return: (r, g, b)
'''
r = 0
g = 0
b = 0
if val > self.val_limit:
val = self.val_limit
if sat == 0:
r = val
g = val
b = val
else:
base = ((100 - sat) * val) / 100
color = (val - base) * ((hue % 60) / 60)
x = int(hue / 60)
if x == 0:
r = val
g = base + color
b = base
elif x == 1:
r = val - color
g = val
b = base
elif x == 2:
r = base
g = val
b = base + color
elif x == 3:
r = base
g = val - color
b = val
elif x == 4:
r = base + color
g = base
b = val
elif x == 5:
r = val
g = base
b = val - color
return int(r), int(g), int(b)
def hsv_to_rgbw(self, hue, sat, val):
'''
Converts HSV values, and returns a tuple of RGBW values
:param hue:
:param sat:
:param val:
:return: (r, g, b, w)
'''
rgb = self.hsv_to_rgb(hue, sat, val)
return rgb[0], rgb[1], rgb[2], min(rgb)
def set_hsv(self, hue, sat, val, index):
'''
Takes HSV values and displays it on a single LED/Neopixel
:param hue:
:param sat:
:param val:
:param index: Index of LED/Pixel
'''
if self.neopixel:
if self.rgbw:
self.set_rgb(self.hsv_to_rgbw(hue, sat, val), index)
else:
self.set_rgb(self.hsv_to_rgb(hue, sat, val), index)
def set_hsv_fill(self, hue, sat, val):
'''
Takes HSV values and displays it on all LEDs/Neopixels
:param hue:
:param sat:
:param val:
'''
if self.neopixel:
if self.rgbw:
self.set_rgb_fill(self.hsv_to_rgbw(hue, sat, val))
else:
self.set_rgb_fill(self.hsv_to_rgb(hue, sat, val))
def set_rgb(self, rgb, index):
'''
Takes an RGB or RGBW and displays it on a single LED/Neopixel
:param rgb: RGB or RGBW
:param index: Index of LED/Pixel
'''
if self.neopixel and 0 <= index <= self.num_pixels - 1:
self.neopixel[index] = rgb
if not self.disable_auto_write:
self.neopixel.show()
def set_rgb_fill(self, rgb):
'''
Takes an RGB or RGBW and displays it on all LEDs/Neopixels
:param rgb: RGB or RGBW
'''
if self.neopixel:
self.neopixel.fill(rgb)
if not self.disable_auto_write:
self.neopixel.show()
def increase_hue(self, step=None):
'''
Increases hue by step amount rolling at 360 and returning to 0
:param step:
'''
if not step:
step = self.hue_step
self.hue = (self.hue + step) % 360
if self._check_update():
self._do_update()
def decrease_hue(self, step=None):
'''
Decreases hue by step amount rolling at 0 and returning to 360
:param step:
'''
if not step:
step = self.hue_step
if (self.hue - step) <= 0:
self.hue = (self.hue + 360 - step) % 360
else:
self.hue = (self.hue - step) % 360
if self._check_update():
self._do_update()
def increase_sat(self, step=None):
'''
Increases saturation by step amount stopping at 100
:param step:
'''
if not step:
step = self.sat_step
if self.sat + step >= 100:
self.sat = 100
else:
self.sat += step
if self._check_update():
self._do_update()
def decrease_sat(self, step=None):
'''
Decreases saturation by step amount stopping at 0
:param step:
'''
if not step:
step = self.sat_step
if (self.sat - step) <= 0:
self.sat = 0
else:
self.sat -= step
if self._check_update():
self._do_update()
def increase_val(self, step=None):
'''
Increases value by step amount stopping at 100
:param step:
'''
if not step:
step = self.val_step
if (self.val + step) >= 100:
self.val = 100
else:
self.val += step
if self._check_update():
self._do_update()
def decrease_val(self, step=None):
'''
Decreases value by step amount stopping at 0
:param step:
'''
if not step:
step = self.val_step
if (self.val - step) <= 0:
self.val = 0
else:
self.val -= step
if self._check_update():
self._do_update()
def increase_ani(self):
'''
Increases animation speed by 1 amount stopping at 10
:param step:
'''
if (self.animation_speed + 1) > 10:
self.animation_speed = 10
else:
self.animation_speed += 1
if self._check_update():
self._do_update()
def decrease_ani(self):
'''
Decreases animation speed by 1 amount stopping at 0
:param step:
'''
if (self.animation_speed - 1) <= 0:
self.animation_speed = 0
else:
self.animation_speed -= 1
if self._check_update():
self._do_update()
def off(self):
'''
Turns off all LEDs/Neopixels without changing stored values
'''
if self.neopixel:
self.set_hsv_fill(0, 0, 0)
def show(self):
'''
Turns on all LEDs/Neopixels without changing stored values
'''
if self.neopixel:
self.neopixel.show()
def animate(self):
'''
Activates a "step" in the animation based on the active mode
:return: Returns the new state in animation
'''
if self.effect_init:
self._init_effect()
if self.animation_mode is not AnimationModes.STATIC_STANDBY:
self.loopcounter += 1
if self.loopcounter >= 7 and self.enable:
self.loopcounter = 0
if self.animation_mode == AnimationModes.BREATHING:
self.effect_breathing()
elif self.animation_mode == AnimationModes.RAINBOW:
self.effect_rainbow()
elif self.animation_mode == AnimationModes.BREATHING_RAINBOW:
self.effect_breathing_rainbow()
elif self.animation_mode == AnimationModes.STATIC:
self.effect_static()
elif self.animation_mode == AnimationModes.KNIGHT:
self.effect_knight()
elif self.animation_mode == AnimationModes.SWIRL:
self.effect_swirl()
elif self.animation_mode == AnimationModes.USER:
self.user_animation(self)
elif self.animation_mode == AnimationModes.STATIC_STANDBY:
pass
else:
self.off()
if self.loopcounter >= 7:
self.loopcounter = 0
def _animation_step(self):
interval = self.time_ms() - self.time
if interval >= max(self.intervals):
self.time = self.time_ms()
return max(self.intervals)
if interval in self.intervals:
return interval
return None
def _init_effect(self):
if (
self.animation_mode == AnimationModes.BREATHING
or self.animation_mode == AnimationModes.BREATHING_RAINBOW
):
self.intervals = (30, 20, 10, 5)
elif self.animation_mode == AnimationModes.SWIRL:
self.intervals = (50, 50)
self.pos = 0
self.reverse_animation = False
self.effect_init = False
def _check_update(self):
return bool(self.animation_mode == AnimationModes.STATIC_STANDBY)
def _do_update(self):
if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC
def effect_static(self):
self.set_hsv_fill(self.hue, self.sat, self.val)
self.animation_mode = AnimationModes.STATIC_STANDBY
def effect_breathing(self):
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
sined = sin((self.pos / 255.0) * pi)
multip_1 = exp(sined) - self.breathe_center / e
multip_2 = self.val_limit / (e - 1 / e)
self.val = int(multip_1 * multip_2)
self.pos = (self.pos + self.animation_speed) % 256
self.set_hsv_fill(self.hue, self.sat, self.val)
def effect_breathing_rainbow(self):
self.increase_hue(self.animation_speed)
self.effect_breathing()
def effect_rainbow(self):
self.increase_hue(self.animation_speed)
self.set_hsv_fill(self.hue, self.sat, self.val)
def effect_swirl(self):
self.increase_hue(self.animation_speed)
self.disable_auto_write = True # Turn off instantly showing
for i in range(0, self.num_pixels):
self.set_hsv(
(self.hue - (i * self.num_pixels)) % 360, self.sat, self.val, i
)
# Show final results
self.disable_auto_write = False # Resume showing changes
self.show()
def effect_knight(self):
# Determine which LEDs should be lit up
self.disable_auto_write = True # Turn off instantly showing
self.off() # Fill all off
pos = int(self.pos)
# Set all pixels on in range of animation length offset by position
for i in range(pos, (pos + self.knight_effect_length)):
self.set_hsv(self.hue, self.sat, self.val, i)
# Reverse animation when a boundary is hit
if pos >= self.num_pixels or pos - 1 < (self.knight_effect_length * -1):
self.reverse_animation = not self.reverse_animation
if self.reverse_animation:
self.pos -= self.animation_speed / 2
else:
self.pos += self.animation_speed / 2
# Show final results
self.disable_auto_write = False # Resume showing changes
self.show()
def _rgb_tog(self, *args, **kwargs):
if self.animation_mode == AnimationModes.STATIC:
self.animation_mode = AnimationModes.STATIC_STANDBY
self._do_update()
if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC
self._do_update()
if self.enable:
self.off()
self.enable = not self.enable
def _rgb_hui(self, *args, **kwargs):
self.increase_hue()
def _rgb_hud(self, *args, **kwargs):
self.decrease_hue()
def _rgb_sai(self, *args, **kwargs):
self.increase_sat()
def _rgb_sad(self, *args, **kwargs):
self.decrease_sat()
def _rgb_vai(self, *args, **kwargs):
self.increase_val()
def _rgb_vad(self, *args, **kwargs):
self.decrease_val()
def _rgb_ani(self, *args, **kwargs):
self.increase_ani()
def _rgb_and(self, *args, **kwargs):
self.decrease_ani()
def _rgb_mode_static(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.STATIC
def _rgb_mode_breathe(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.BREATHING
def _rgb_mode_breathe_rainbow(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.BREATHING_RAINBOW
def _rgb_mode_rainbow(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.RAINBOW
def _rgb_mode_swirl(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.SWIRL
def _rgb_mode_knight(self, *args, **kwargs):
self.effect_init = True
self.animation_mode = AnimationModes.KNIGHT
def _rgb_reset(self, *args, **kwargs):
self.hue = self.hue_default
self.sat = self.sat_default
self.val = self.val_default
if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC
self._do_update()

View File

@@ -1,103 +0,0 @@
import busio
import gc
from kmk.extensions import Extension
from kmk.kmktime import sleep_ms
from kmk.matrix import intify_coordinate
class SplitType:
UART = 1
I2C = 2 # unused
ONEWIRE = 3 # unused
BLE = 4 # unused
class Split(Extension):
def __init__(
self,
extra_data_pin=None,
offsets=(),
flip=False,
side=None,
stype=None,
master_left=True,
uart_flip=True,
uart_pin=None,
uart_timeout=20,
):
self.extra_data_pin = extra_data_pin
self.split_offsets = offsets
self.split_flip = flip
self.split_side = side
self.split_type = stype
self.split_master_left = master_left
self._uart = None
self.uart_flip = uart_flip
self.uart_pin = uart_pin
self.uart_timeout = uart_timeout
def during_bootup(self, keyboard):
if self.split_type is not None:
try:
# Working around https://github.com/adafruit/circuitpython/issues/1769
keyboard._hid_helper_inst.create_report([]).send()
self._is_master = True
# Sleep 2s so master portion doesn't "appear" to boot quicker than
# dependent portions (which will take ~2s to time out on the HID send)
sleep_ms(2000)
except OSError:
self._is_master = False
if self.split_flip and not self._is_master:
keyboard.col_pins = list(reversed(self.col_pins))
if self.split_side == 'Left':
self.split_master_left = self._is_master
elif self.split_side == 'Right':
self.split_master_left = not self._is_master
else:
self._is_master = True
if self.uart_pin is not None:
if self._is_master:
self._uart = busio.UART(
tx=None, rx=self.uart_pin, timeout=self.uart_timeout
)
else:
self._uart = busio.UART(
tx=self.uart_pin, rx=None, timeout=self.uart_timeout
)
# Attempt to sanely guess a coord_mapping if one is not provided.
if not keyboard.coord_mapping:
keyboard.coord_mapping = []
rows_to_calc = len(keyboard.row_pins)
cols_to_calc = len(keyboard.col_pins)
if self.split_offsets:
rows_to_calc *= 2
cols_to_calc *= 2
for ridx in range(rows_to_calc):
for cidx in range(cols_to_calc):
keyboard.coord_mapping.append(intify_coordinate(ridx, cidx))
gc.collect()
def before_matrix_scan(self, keyboard_state):
if self.split_type is not None and self._is_master:
return self._receive_from_slave()
def after_matrix_scan(self, keyboard_state, matrix_update):
if matrix_update is not None and not self._is_master:
self._send_to_master(matrix_update)
def _send_to_master(self, update):
if self.split_master_left:
update[1] += self.split_offsets[update[0]]
else:
update[1] -= self.split_offsets[update[0]]
if self._uart is not None:
self._uart.write(update)