Initial
This commit is contained in:
commit
4c75ff8edd
64 files changed
+8392
No files matched your search
@@ -0,0 +1,51 @@
|
||||
class InvalidExtensionEnvironment(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Extension:
|
||||
_enabled = True
|
||||
|
||||
def enable(self, keyboard):
|
||||
self._enabled = True
|
||||
|
||||
self.on_runtime_enable(keyboard)
|
||||
|
||||
def disable(self, keyboard):
|
||||
self._enabled = False
|
||||
|
||||
self.on_runtime_disable(keyboard)
|
||||
|
||||
# The below methods should be implemented by subclasses
|
||||
|
||||
def on_runtime_enable(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def on_runtime_disable(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def during_bootup(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def before_matrix_scan(self, keyboard):
|
||||
'''
|
||||
Return value will be injected as an extra matrix update
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def after_matrix_scan(self, keyboard):
|
||||
'''
|
||||
Return value will be replace matrix update if supplied
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def before_hid_send(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def after_hid_send(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def on_powersave_enable(self, keyboard):
|
||||
raise NotImplementedError
|
||||
|
||||
def on_powersave_disable(self, keyboard):
|
||||
raise NotImplementedError
|
||||
@@ -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
|
||||
@@ -0,0 +1,34 @@
|
||||
# What's this?
|
||||
# This is a keycode conversion script. With this, KMK will work as a JIS keyboard.
|
||||
|
||||
# Usage
|
||||
# ```python
|
||||
# import kmk.extensions.keymap_extras.keymap_jp
|
||||
# ```
|
||||
|
||||
from kmk.keys import KC
|
||||
|
||||
KC.CIRC = KC.EQL # ^
|
||||
KC.AT = KC.LBRC # @
|
||||
KC.LBRC = KC.RBRC # [
|
||||
KC.EISU = KC.CAPS # Eisū (英数)
|
||||
KC.COLN = KC.QUOT # :
|
||||
KC.LCBR = KC.LSFT(KC.RBRC) # {
|
||||
KC.RBRC = KC.NUHS # ]
|
||||
KC.BSLS = KC.INT1 # (backslash)
|
||||
KC.PLUS = KC.LSFT(KC.SCLN)
|
||||
KC.TILD = KC.LSFT(KC.EQL) # ~
|
||||
KC.GRV = KC.LSFT(KC.AT) # `
|
||||
KC.DQUO = KC.LSFT(KC.N2) # "
|
||||
KC.AMPR = KC.LSFT(KC.N6) # &
|
||||
KC.ASTR = KC.LSFT(KC.QUOT) # *
|
||||
KC.QUOT = KC.LSFT(KC.N7) # '
|
||||
KC.LPRN = KC.LSFT(KC.N8) # (
|
||||
KC.RPRN = KC.LSFT(KC.N9) # )
|
||||
KC.EQL = KC.LSFT(KC.MINS) # =
|
||||
KC.PIPE = KC.LSFT(KC.INT3) # |
|
||||
KC.RCBR = KC.LSFT(KC.NUHS) # }
|
||||
KC.LABK = KC.LSFT(KC.COMM) # <
|
||||
KC.RABK = KC.LSFT(KC.DOT) # >
|
||||
KC.QUES = KC.LSFT(KC.SLSH) # ?
|
||||
KC.UNDS = KC.LSFT(KC.INT1) # _
|
||||
@@ -0,0 +1,256 @@
|
||||
import pwmio
|
||||
from math import e, exp, pi, sin
|
||||
|
||||
from kmk.extensions import Extension, InvalidExtensionEnvironment
|
||||
from kmk.keys import make_argumented_key, make_key
|
||||
from kmk.utils import clamp
|
||||
|
||||
|
||||
class LEDKeyMeta:
|
||||
def __init__(self, *leds):
|
||||
self.leds = leds
|
||||
self.brightness = None
|
||||
|
||||
|
||||
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:
|
||||
pins_iter = iter(led_pin)
|
||||
except TypeError:
|
||||
pins_iter = [led_pin]
|
||||
|
||||
try:
|
||||
self._leds = [pwmio.PWMOut(pin) for pin in pins_iter]
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise InvalidExtensionEnvironment(
|
||||
'Unable to create pwmio.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_argumented_key(
|
||||
names=('LED_TOG',),
|
||||
validator=self._led_key_validator,
|
||||
on_press=self._key_led_tog,
|
||||
)
|
||||
make_argumented_key(
|
||||
names=('LED_INC',),
|
||||
validator=self._led_key_validator,
|
||||
on_press=self._key_led_inc,
|
||||
)
|
||||
make_argumented_key(
|
||||
names=('LED_DEC',),
|
||||
validator=self._led_key_validator,
|
||||
on_press=self._key_led_dec,
|
||||
)
|
||||
make_argumented_key(
|
||||
names=('LED_SET',),
|
||||
validator=self._led_set_key_validator,
|
||||
on_press=self._key_led_set,
|
||||
)
|
||||
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, leds=None):
|
||||
leds = leds or range(0, len(self._leds))
|
||||
for i in leds:
|
||||
self._leds[i].duty_cycle = int(percent / 100 * 65535)
|
||||
|
||||
def step_brightness(self, step, leds=None):
|
||||
leds = leds or range(0, len(self._leds))
|
||||
for i in leds:
|
||||
brightness = int(self._leds[i].duty_cycle / 65535 * 100) + step
|
||||
self.set_brightness(clamp(brightness), [i])
|
||||
|
||||
def increase_brightness(self, step=None, leds=None):
|
||||
if step is None:
|
||||
step = self.brightness_step
|
||||
self.step_brightness(step, leds)
|
||||
|
||||
def decrease_brightness(self, step=None, leds=None):
|
||||
if step is None:
|
||||
step = self.brightness_step
|
||||
self.step_brightness(-step, leds)
|
||||
|
||||
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 _led_key_validator(self, *leds):
|
||||
if leds:
|
||||
for led in leds:
|
||||
assert self._leds[led]
|
||||
return LEDKeyMeta(*leds)
|
||||
|
||||
def _led_set_key_validator(self, brightness, *leds):
|
||||
meta = self._led_key_validator(*leds)
|
||||
meta.brightness = brightness
|
||||
return meta
|
||||
|
||||
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, key, *args, **kwargs):
|
||||
self.increase_brightness(leds=key.meta.leds)
|
||||
|
||||
def _key_led_dec(self, key, *args, **kwargs):
|
||||
self.decrease_brightness(leds=key.meta.leds)
|
||||
|
||||
def _key_led_set(self, key, *args, **kwargs):
|
||||
self.set_brightness(percent=key.meta.brightness, leds=key.meta.leds)
|
||||
|
||||
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
|
||||
@@ -0,0 +1,65 @@
|
||||
import usb_hid
|
||||
|
||||
from kmk.extensions import Extension
|
||||
from kmk.hid import HIDUsage
|
||||
|
||||
|
||||
class LockCode:
|
||||
NUMLOCK = 0x01
|
||||
CAPSLOCK = 0x02
|
||||
SCROLLLOCK = 0x04
|
||||
COMPOSE = 0x08
|
||||
KANA = 0x10
|
||||
RESERVED = 0x20
|
||||
|
||||
|
||||
class LockStatus(Extension):
|
||||
def __init__(self):
|
||||
self.report = 0x00
|
||||
self.hid = None
|
||||
for device in usb_hid.devices:
|
||||
if device.usage == HIDUsage.KEYBOARD:
|
||||
self.hid = device
|
||||
|
||||
def __repr__(self):
|
||||
return ('LockStatus(report={})').format(self.report)
|
||||
|
||||
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.hid:
|
||||
report = self.hid.get_last_received_report()
|
||||
if report[0] != self.report:
|
||||
self.report = report[0]
|
||||
return
|
||||
|
||||
def on_powersave_enable(self, sandbox):
|
||||
return
|
||||
|
||||
def on_powersave_disable(self, sandbox):
|
||||
return
|
||||
|
||||
def get_num_lock(self):
|
||||
return bool(self.report & LockCode.NUMLOCK)
|
||||
|
||||
def get_caps_lock(self):
|
||||
return bool(self.report & LockCode.CAPSLOCK)
|
||||
|
||||
def get_scroll_lock(self):
|
||||
return bool(self.report & LockCode.SCROLLLOCK)
|
||||
|
||||
def get_compose(self):
|
||||
return bool(self.report & LockCode.COMPOSE)
|
||||
|
||||
def get_kana(self):
|
||||
return bool(self.report & LockCode.KANA)
|
||||
@@ -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
|
||||
@@ -0,0 +1,582 @@
|
||||
from adafruit_pixelbuf import PixelBuf
|
||||
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
|
||||
from kmk.kmktime import PeriodicTimer
|
||||
from kmk.utils import clamp
|
||||
|
||||
rgb_config = {}
|
||||
|
||||
|
||||
def hsv_to_rgb(hue, sat, val):
|
||||
'''
|
||||
Converts HSV values, and returns a tuple of RGB values
|
||||
:param hue:
|
||||
:param sat:
|
||||
:param val:
|
||||
:return: (r, g, b)
|
||||
'''
|
||||
if sat == 0:
|
||||
return (val, val, val)
|
||||
|
||||
hue = 6 * (hue & 0xFF)
|
||||
frac = hue & 0xFF
|
||||
sxt = hue >> 8
|
||||
|
||||
base = (0xFF - sat) * val
|
||||
color = (val * sat * frac) >> 8
|
||||
val <<= 8
|
||||
|
||||
if sxt == 0:
|
||||
r = val
|
||||
g = base + color
|
||||
b = base
|
||||
elif sxt == 1:
|
||||
r = val - color
|
||||
g = val
|
||||
b = base
|
||||
elif sxt == 2:
|
||||
r = base
|
||||
g = val
|
||||
b = base + color
|
||||
elif sxt == 3:
|
||||
r = base
|
||||
g = val - color
|
||||
b = val
|
||||
elif sxt == 4:
|
||||
r = base + color
|
||||
g = base
|
||||
b = val
|
||||
elif sxt == 5:
|
||||
r = val
|
||||
g = base
|
||||
b = val - color
|
||||
|
||||
return (r >> 8), (g >> 8), (b >> 8)
|
||||
|
||||
|
||||
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 = hsv_to_rgb(hue, sat, val)
|
||||
return rgb[0], rgb[1], rgb[2], min(rgb)
|
||||
|
||||
|
||||
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
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pixel_pin,
|
||||
num_pixels=0,
|
||||
val_limit=255,
|
||||
hue_default=0,
|
||||
sat_default=255,
|
||||
rgb_order=(1, 0, 2), # GRB WS2812
|
||||
val_default=255,
|
||||
hue_step=4,
|
||||
sat_step=13,
|
||||
val_step=13,
|
||||
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,
|
||||
pixels=None,
|
||||
refresh_rate=60,
|
||||
):
|
||||
if pixels is None:
|
||||
import neopixel
|
||||
|
||||
pixels = neopixel.NeoPixel(
|
||||
pixel_pin,
|
||||
num_pixels,
|
||||
pixel_order=rgb_order,
|
||||
auto_write=not disable_auto_write,
|
||||
)
|
||||
self.pixels = pixels
|
||||
self.num_pixels = num_pixels
|
||||
|
||||
# PixelBuffer are already iterable, can't do the usual `try: iter(...)`
|
||||
if issubclass(self.pixels.__class__, PixelBuf):
|
||||
self.pixels = (self.pixels,)
|
||||
|
||||
if self.num_pixels == 0:
|
||||
for pixels in self.pixels:
|
||||
self.num_pixels += len(pixels)
|
||||
|
||||
self.rgbw = bool(len(rgb_order) == 4)
|
||||
|
||||
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.refresh_rate = refresh_rate
|
||||
|
||||
self._substep = 0
|
||||
|
||||
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):
|
||||
self._timer = PeriodicTimer(1000 // self.refresh_rate)
|
||||
|
||||
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()
|
||||
|
||||
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.rgbw:
|
||||
self.set_rgb(hsv_to_rgbw(hue, sat, val), index)
|
||||
else:
|
||||
self.set_rgb(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.rgbw:
|
||||
self.set_rgb_fill(hsv_to_rgbw(hue, sat, val))
|
||||
else:
|
||||
self.set_rgb_fill(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 0 <= index <= self.num_pixels - 1:
|
||||
for pixels in self.pixels:
|
||||
if index <= (len(pixels) - 1):
|
||||
break
|
||||
index -= len(pixels)
|
||||
|
||||
pixels[index] = rgb
|
||||
|
||||
if not self.disable_auto_write:
|
||||
pixels.show()
|
||||
|
||||
def set_rgb_fill(self, rgb):
|
||||
'''
|
||||
Takes an RGB or RGBW and displays it on all LEDs/Neopixels
|
||||
:param rgb: RGB or RGBW
|
||||
'''
|
||||
for pixels in self.pixels:
|
||||
pixels.fill(rgb)
|
||||
if not self.disable_auto_write:
|
||||
pixels.show()
|
||||
|
||||
def increase_hue(self, step=None):
|
||||
'''
|
||||
Increases hue by step amount rolling at 256 and returning to 0
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.hue_step
|
||||
|
||||
self.hue = (self.hue + step) % 256
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def decrease_hue(self, step=None):
|
||||
'''
|
||||
Decreases hue by step amount rolling at 0 and returning to 256
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.hue_step
|
||||
|
||||
if (self.hue - step) <= 0:
|
||||
self.hue = (self.hue + 256 - step) % 256
|
||||
else:
|
||||
self.hue = (self.hue - step) % 256
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def increase_sat(self, step=None):
|
||||
'''
|
||||
Increases saturation by step amount stopping at 255
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.sat_step
|
||||
|
||||
self.sat = clamp(self.sat + step, 0, 255)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def decrease_sat(self, step=None):
|
||||
'''
|
||||
Decreases saturation by step amount stopping at 0
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.sat_step
|
||||
|
||||
self.sat = clamp(self.sat - step, 0, 255)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def increase_val(self, step=None):
|
||||
'''
|
||||
Increases value by step amount stopping at 100
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.val_step
|
||||
|
||||
self.val = clamp(self.val + step, 0, 255)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def decrease_val(self, step=None):
|
||||
'''
|
||||
Decreases value by step amount stopping at 0
|
||||
:param step:
|
||||
'''
|
||||
if step is None:
|
||||
step = self.val_step
|
||||
|
||||
self.val = clamp(self.val - step, 0, 255)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def increase_ani(self):
|
||||
'''
|
||||
Increases animation speed by 1 amount stopping at 10
|
||||
:param step:
|
||||
'''
|
||||
self.animation_speed = clamp(self.animation_speed + 1, 0, 10)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def decrease_ani(self):
|
||||
'''
|
||||
Decreases animation speed by 1 amount stopping at 0
|
||||
:param step:
|
||||
'''
|
||||
self.animation_speed = clamp(self.animation_speed - 1, 0, 10)
|
||||
|
||||
if self._check_update():
|
||||
self._do_update()
|
||||
|
||||
def off(self):
|
||||
'''
|
||||
Turns off all LEDs/Neopixels without changing stored values
|
||||
'''
|
||||
self.set_hsv_fill(0, 0, 0)
|
||||
|
||||
def show(self):
|
||||
'''
|
||||
Turns on all LEDs/Neopixels without changing stored values
|
||||
'''
|
||||
for pixels in self.pixels:
|
||||
pixels.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 AnimationModes.STATIC_STANDBY:
|
||||
return
|
||||
|
||||
if self.enable and self._timer.tick():
|
||||
self._animation_step()
|
||||
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()
|
||||
|
||||
def _animation_step(self):
|
||||
self._substep += self.animation_speed / 4
|
||||
self._step = int(self._substep)
|
||||
self._substep -= self._step
|
||||
|
||||
def _init_effect(self):
|
||||
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._step) % 256
|
||||
self.set_hsv_fill(self.hue, self.sat, self.val)
|
||||
|
||||
def effect_breathing_rainbow(self):
|
||||
self.increase_hue(self._step)
|
||||
self.effect_breathing()
|
||||
|
||||
def effect_rainbow(self):
|
||||
self.increase_hue(self._step)
|
||||
self.set_hsv_fill(self.hue, self.sat, self.val)
|
||||
|
||||
def effect_swirl(self):
|
||||
self.increase_hue(self._step)
|
||||
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)) % 256, 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._step / 2
|
||||
else:
|
||||
self.pos += self._step / 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()
|
||||
@@ -0,0 +1,145 @@
|
||||
# Use this extension for showing layer status with three leds
|
||||
|
||||
import pwmio
|
||||
import time
|
||||
|
||||
from kmk.extensions import Extension, InvalidExtensionEnvironment
|
||||
from kmk.keys import make_key
|
||||
|
||||
|
||||
class statusLED(Extension):
|
||||
def __init__(
|
||||
self,
|
||||
led_pins,
|
||||
brightness=30,
|
||||
brightness_step=5,
|
||||
brightness_limit=100,
|
||||
):
|
||||
self._leds = []
|
||||
for led in led_pins:
|
||||
try:
|
||||
self._leds.append(pwmio.PWMOut(led))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise InvalidExtensionEnvironment(
|
||||
'Unable to create pulseio.PWMOut() instance with provided led_pin'
|
||||
)
|
||||
self._led_count = len(self._leds)
|
||||
|
||||
self.brightness = brightness
|
||||
self._layer_last = -1
|
||||
|
||||
self.brightness_step = brightness_step
|
||||
self.brightness_limit = brightness_limit
|
||||
|
||||
make_key(names=('SLED_INC',), on_press=self._key_led_inc)
|
||||
make_key(names=('SLED_DEC',), on_press=self._key_led_dec)
|
||||
|
||||
def _layer_indicator(self, layer_active, *args, **kwargs):
|
||||
'''
|
||||
Indicates layer with leds
|
||||
|
||||
For the time being just a simple consecutive single led
|
||||
indicator. And when there are more layers than leds it
|
||||
wraps around to the first led again.
|
||||
(Also works for a single led, which just lights when any
|
||||
layer is active)
|
||||
'''
|
||||
|
||||
if self._layer_last != layer_active:
|
||||
led_last = 0 if self._layer_last == 0 else 1 + (self._layer_last - 1) % 3
|
||||
if layer_active > 0:
|
||||
led_active = 0 if layer_active == 0 else 1 + (layer_active - 1) % 3
|
||||
self.set_brightness(self.brightness, led_active)
|
||||
self.set_brightness(0, led_last)
|
||||
else:
|
||||
self.set_brightness(0, led_last)
|
||||
self._layer_last = layer_active
|
||||
|
||||
def __repr__(self):
|
||||
return 'SLED({})'.format(self._to_dict())
|
||||
|
||||
def _to_dict(self):
|
||||
return {
|
||||
'_brightness': self.brightness,
|
||||
'brightness_step': self.brightness_step,
|
||||
'brightness_limit': self.brightness_limit,
|
||||
}
|
||||
|
||||
def on_runtime_enable(self, sandbox):
|
||||
return
|
||||
|
||||
def on_runtime_disable(self, sandbox):
|
||||
return
|
||||
|
||||
def during_bootup(self, sandbox):
|
||||
'''Light up every single led once for 200 ms'''
|
||||
for i in range(self._led_count + 2):
|
||||
if i < self._led_count:
|
||||
self._leds[i].duty_cycle = int(self.brightness / 100 * 65535)
|
||||
i_off = i - 2
|
||||
if i_off >= 0 and i_off < self._led_count:
|
||||
self._leds[i_off].duty_cycle = int(0)
|
||||
time.sleep(0.1)
|
||||
for led in self._leds:
|
||||
led.duty_cycle = int(0)
|
||||
return
|
||||
|
||||
def before_matrix_scan(self, sandbox):
|
||||
return
|
||||
|
||||
def after_matrix_scan(self, sandbox):
|
||||
self._layer_indicator(sandbox.active_layers[0])
|
||||
return
|
||||
|
||||
def before_hid_send(self, sandbox):
|
||||
return
|
||||
|
||||
def after_hid_send(self, sandbox):
|
||||
return
|
||||
|
||||
def on_powersave_enable(self, sandbox):
|
||||
self.set_brightness(0)
|
||||
return
|
||||
|
||||
def on_powersave_disable(self, sandbox):
|
||||
self.set_brightness(self._brightness)
|
||||
self._leds[2].duty_cycle = int(50 / 100 * 65535)
|
||||
time.sleep(0.2)
|
||||
self._leds[2].duty_cycle = int(0)
|
||||
return
|
||||
|
||||
def set_brightness(self, percent, layer_id=-1):
|
||||
if layer_id < 0:
|
||||
for led in self._leds:
|
||||
led.duty_cycle = int(percent / 100 * 65535)
|
||||
else:
|
||||
self._leds[layer_id - 1].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, self._layer_last)
|
||||
|
||||
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, self._layer_last)
|
||||
|
||||
def _key_led_inc(self, *args, **kwargs):
|
||||
self.increase_brightness()
|
||||
|
||||
def _key_led_dec(self, *args, **kwargs):
|
||||
self.decrease_brightness()
|
||||
Reference in new issue
Block a user