Adafruit_Learning_System_Gu.../Launch_Deck_Trellis_M4/code.py
2022-02-23 12:56:10 -05:00

159 lines
6.3 KiB
Python

# SPDX-FileCopyrightText: 2018 John Edgar Park for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Launch Deck Trellis M4
# USB HID button box for launching applications, media control, camera switching and more
# Use it with your favorite keyboard controlled launcher, such as Quicksilver and AutoHotkey
import time
import random
import adafruit_trellism4
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
# Rotation of the trellis. 0 is when the USB is upself.
# The grid coordinates used below require portrait mode of 90 or 270
ROTATION = 270
# the two command types -- MEDIA for ConsumerControlCodes, KEY for Keycodes
# this allows button press to send the correct HID command for the type specified
MEDIA = 1
KEY = 2
# button mappings
# customize these for your desired postitions, colors, and keyboard combos
# specify (button coordinate): (color hex value, command type, command/keycodes)
keymap = {
(0,0): (0x001100, MEDIA, ConsumerControlCode.PLAY_PAUSE),
(1,0): (0x110011, MEDIA, ConsumerControlCode.SCAN_PREVIOUS_TRACK),
(2,0): (0x110011, MEDIA, ConsumerControlCode.SCAN_NEXT_TRACK),
(3,0): (0x000033, MEDIA, ConsumerControlCode.VOLUME_INCREMENT),
(0,1): (0x110000, MEDIA, ConsumerControlCode.MUTE),
# intentional blank button
# intentional blank button
(3,1): ((0,0,10), MEDIA, ConsumerControlCode.VOLUME_DECREMENT),
(0,2): (0x551100, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.ONE)),
(1,2): (0x221100, KEY, (Keycode.CONTROL, Keycode.SHIFT, Keycode.TAB)), # back cycle tabs
(2,2): (0x221100, KEY, (Keycode.CONTROL, Keycode.TAB)), # cycle tabs
(3,2): (0x333300, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.TWO)),
(0,3): (0x001155, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.THREE)),
# intentional blank button
# intentional blank button
(3,3): (0x330000, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.FOUR)),
(0,4): (0x005511, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.FIVE)),
(1,4): (0x440000, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.SIX)),
# intentional blank button
(3,4): (0x003300, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.EIGHT)),
(0,5): (0x222222, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.W)),
(1,5): (0x000044, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.E)),
# intentional blank button
(3,5): (0x332211, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.T)),
(0,6): (0x001133, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.C)),
(1,6): (0x331100, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.V)),
(2,6): (0x111111, KEY, (Keycode.GUI, Keycode.SHIFT, Keycode.FOUR)), # screen shot
(3,6): (0x110000, KEY, (Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.N)),
(0,7): (0x060606, KEY, (Keycode.GUI, Keycode.H)), # hide front app, all windows
(1,7): (0x222200, KEY, (Keycode.GUI, Keycode.GRAVE_ACCENT)), # cycle windows of app
(2,7): (0x010001, KEY, (Keycode.GUI, Keycode.SHIFT, Keycode.TAB)), # cycle apps backards
(3,7): (0x010001, KEY, (Keycode.GUI, Keycode.TAB))} # cycle apps forwards
# Time in seconds to stay lit before sleeping.
TIMEOUT = 90
# Time to take fading out all of the keys.
FADE_TIME = 1
# Once asleep, how much time to wait between "snores" which fade up and down one button.
SNORE_PAUSE = 0.5
# Time in seconds to take fading up the snoring LED.
SNORE_UP = 2
# Time in seconds to take fading down the snoring LED.
SNORE_DOWN = 1
TOTAL_SNORE = SNORE_PAUSE + SNORE_UP + SNORE_DOWN
kbd = Keyboard(usb_hid.devices)
cc = ConsumerControl(usb_hid.devices)
trellis = adafruit_trellism4.TrellisM4Express(rotation=ROTATION)
for button in keymap:
trellis.pixels[button] = keymap[button][0]
current_press = set()
last_press = time.monotonic()
snore_count = -1
while True:
pressed = set(trellis.pressed_keys)
now = time.monotonic()
sleep_time = now - last_press
sleeping = sleep_time > TIMEOUT
for down in pressed - current_press:
if down in keymap and not sleeping:
print("down", down)
# Lower the brightness so that we don't draw too much current when we turn all of
# the LEDs on.
trellis.pixels.brightness = 0.2
trellis.pixels.fill(keymap[down][0])
if keymap[down][1] == KEY:
kbd.press(*keymap[down][2])
else:
cc.send(keymap[down][2])
# else if the entry starts with 'l' for layout.write
last_press = now
for up in current_press - pressed:
if up in keymap:
print("up", up)
if keymap[up][1] == KEY:
kbd.release(*keymap[up][2])
# Reset the LEDs when there was something previously pressed (current_press) but nothing now
# (pressed).
if not pressed and current_press:
trellis.pixels.brightness = 1
trellis.pixels.fill((0, 0, 0))
for button in keymap:
trellis.pixels[button] = keymap[button][0]
if not sleeping:
snore_count = -1
else:
sleep_time -= TIMEOUT
# Fade all out
if sleep_time < FADE_TIME:
brightness = (1 - sleep_time / FADE_TIME)
# Snore by pausing and then fading a random button up and back down.
else:
sleep_time -= FADE_TIME
current_snore = int(sleep_time / TOTAL_SNORE)
# Detect a new snore and pick a new button
if current_snore > snore_count:
button = random.choice(list(keymap.keys()))
trellis.pixels.fill((0, 0, 0))
trellis.pixels[button] = keymap[button][0]
snore_count = current_snore
sleep_time = sleep_time % TOTAL_SNORE
if sleep_time < SNORE_PAUSE:
brightness = 0
else:
sleep_time -= SNORE_PAUSE
if sleep_time < SNORE_UP:
brightness = sleep_time / SNORE_UP
else:
sleep_time -= SNORE_UP
brightness = 1 - sleep_time / SNORE_DOWN
trellis.pixels.brightness = brightness
current_press = pressed