Initial commit; Added previously untracked files.

This commit is contained in:
eworc778 2025-08-10 17:49:52 +01:00
commit 131878133d
34 changed files with 1818 additions and 0 deletions

430
code.py Normal file
View File

@ -0,0 +1,430 @@
import busio
import board
from board import *
from rainbowio import colorwheel
import waveshare_LCD1602
from digitalio import DigitalInOut, Direction, Pull
import time
import board
import usb_hid
from adafruit_hid.keyboard import Keyboard
from keyboard_layout_win_uk import KeyboardLayout
from keycode_win_uk import Keycode
"""Default I2C ports on boards that have one"""
i2c = busio.I2C(GP19, GP18)
buttonOne = DigitalInOut(board.GP0)
buttonOne.pull = Pull.UP
buttonTwo = DigitalInOut(board.GP1)
buttonTwo.pull = Pull.UP
buttonThree = DigitalInOut(board.GP2)
buttonThree.pull = Pull.UP
kbd = Keyboard(usb_hid.devices)
layout = KeyboardLayout(kbd)
lcd = waveshare_LCD1602.LCD1602(i2c, 16, 2)
lcd.setCursor(0,0)
def macro_parser(macroFileName=(str)):
file = open("macros/" + macroFileName, 'r')
clearScr = 1
lineToShow = ""
holdingKeys = 0
sendCombo = 0
keysToPress = []
for line in file:
print(line)
line = line.replace("\n", "")
workingLine = line
sleepingTime = 0
if line == "HOLD":
holdingKeys = 1
if line == "RELEASE":
if holdingKeys == 1:
sendCombo = 1
if sendCombo == 1:
if len(keysToPress) == 1:
kbd.send(keysToPress[0])
kbd.release_all()
elif len(keysToPress) == 2:
kbd.send(keysToPress[0], keysToPress[1])
kbd.release_all()
elif len(keysToPress) == 3:
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2])
kbd.release_all()
elif len(keysToPress) == 4:
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3])
kbd.release_all()
elif len(keysToPress) == 5:
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4])
kbd.release_all()
elif len(keysToPress) == 6:
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4], keysToPress[5])
kbd.release_all()
sendCombo = 0
holdingKeys = 0
keysToPress = []
if line == "super":
if holdingKeys == 1:
keysToPress.append(Keycode.WINDOWS)
else:
time.sleep(0.1)
kbd.send(Keycode.WINDOWS)
if line == "escape":
if holdingKeys == 1:
keysToPress.append(Keycode.ESCAPE)
else:
time.sleep(0.1)
kbd.send(Keycode.ESCAPE)
if line == "tab":
if holdingKeys == 1:
keysToPress.append(Keycode.TAB)
else:
time.sleep(0.1)
kbd.send(Keycode.TAB)
if line == "windows":
if holdingKeys == 1:
keysToPress.append(Keycode.WINDOWS)
else:
time.sleep(0.1)
kbd.send(Keycode.WINDOWS)
if line == "ctrl":
if holdingKeys == 1:
keysToPress.append(Keycode.LEFT_CONTROL)
else:
time.sleep(0.1)
kbd.send(Keycode.LEFT_CONTROL)
if line == "shift":
if holdingKeys == 1:
keysToPress.append(Keycode.LEFT_SHIFT)
else:
time.sleep(0.1)
kbd.send(Keycode.LEFT_SHIFT)
if line.startswith("LCD_SHOW \""):
line = line.replace("LCD_SHOW \"", "\"")
line = line.replace('"', "")
lineToShow = line
clearScr = 0
if line.startswith("#"):
pass
if line == "":
pass
if line.startswith("WAIT"):
line = line.replace("WAIT", "")
line = line.replace(" ", "")
sleepingTime = line
clearScr = 1
if line.startswith('"') and line.endswith('"'):
lineLength = len(line)
tempLine = ""
currentLine = line
for i in range(0, lineLength):
if i == 0:
pass
elif i != (lineLength - 1):
tempLine = tempLine + currentLine[i]
line = tempLine
if holdingKeys == 0:
layout.write(line)
line = currentLine
if len(tempLine) == 1:
if holdingKeys == 1:
keysToPress.append(layout.keycodes(tempLine)[0])
if line == "downarrow":
if holdingKeys == 1:
keysToPress.append(Keycode.DOWN_ARROW)
else:
time.sleep(0.1)
kbd.send(Keycode.DOWN_ARROW)
elif line == "uparrow":
if holdingKeys == 1:
keysToPress.append(Keycode.UP_ARROW)
else:
time.sleep(0.1)
kbd.send(Keycode.UP_ARROW)
elif line == "leftarrow":
if holdingKeys == 1:
keysToPress.append(Keycode.LEFT_ARROW)
else:
time.sleep(0.1)
kbd.send(Keycode.LEFT_ARROW)
elif line == "space":
if holdingKeys == 1:
keysToPress.append(Keycode.SPACE)
else:
time.sleep(0.1)
kbd.send(Keycode.SPACE)
elif line == "capslock":
if holdingKeys == 1:
keysToPress.append(Keycode.CAPS_LOCK)
else:
time.sleep(0.1)
kbd.send(Keycode.CAPS_LOCK)
elif line == "rightarrow":
if holdingKeys == 1:
keysToPress.append(Keycode.RIGHT_ARROW)
else:
time.sleep(0.1)
kbd.send(Keycode.RIGHT_ARROW)
elif line == "forwardslash":
if holdingKeys == 1:
keysToPress.append(Keycode.FORWARD_SLASH)
else:
time.sleep(0.1)
kbd.send(Keycode.FORWARD_SLASH)
elif line == "backslash":
if holdingKeys == 1:
keysToPress.append(Keycode.BACKSLASH)
else:
time.sleep(0.1)
kbd.send(Keycode.BACKSLASH)
elif line == "backspace":
if holdingKeys == 1:
keysToPress.append(Keycode.BACKSPACE)
else:
time.sleep(0.1)
kbd.send(Keycode.BACKSPACE)
elif line == "enter":
if holdingKeys == 1:
keysToPress.append(Keycode.ENTER)
else:
time.sleep(0.1)
kbd.send(Keycode.ENTER)
print("KEYS_PRESSED: " + str(len(keysToPress)))
if clearScr == 1 and workingLine.startswith("WAIT "):
lcd.clear()
lcd.setCursor(0,1)
lcd.printout("> "+workingLine)
lcd.setCursor(0,0)
lcd.printout(lineToShow)
print(lineToShow)
if lineToShow != "":
lineToShow = ""
else:
lcd.clear()
lcd.setCursor(0,1)
lcd.printout("> "+workingLine)
time.sleep(float(sleepingTime))
time.sleep(0.5)
while True:
if not buttonOne.value:
lcd.clear()
lcd.setCursor(0,0)
lcd.printout("Install Arch")
time.sleep(1)
lcd.clear()
macro_parser("archinstall.mcr")
lcd.clear()
elif not buttonTwo.value:
lcd.clear()
lcd.setCursor(0,0)
lcd.printout("Macro Syntax")
time.sleep(1)
lcd.clear()
macro_parser("syntax.mcr")
lcd.clear()
elif not buttonThree.value:
lcd.clear()
lcd.setCursor(0,0)
lcd.printout("Test Macro")
time.sleep(1)
lcd.clear()
macro_parser("test.mcr")
lcd.clear()
lcd.setCursor(0,0)
lcd.printout("Kico v4")
lcd.setCursor(0,1)
lcd.printout("Hit a key!")

BIN
lib/adafruit_ahtx0.mpy Normal file

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/adafruit_hid/mouse.mpy Normal file

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/keycode_win_uk.mpy Normal file

Binary file not shown.

0
lib/lcd/__init__.py Normal file
View File

View File

@ -0,0 +1,95 @@
# Copyright (C) 2017 Dan Halbert
# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""Low-level interface to PCF8574."""
import busio
import board
import microcontroller
from adafruit_bus_device.i2c_device import I2CDevice
from .lcd import LCD_4BITMODE, LCD_BACKLIGHT, LCD_NOBACKLIGHT, PIN_ENABLE
class I2CPCF8574Interface:
# Bit values to turn backlight on/off. Indexed by a boolean.
_BACKLIGHT_VALUES = (LCD_NOBACKLIGHT, LCD_BACKLIGHT)
def __init__(self, i2c, address):
"""
CharLCD via PCF8574 I2C port expander.
Pin mapping::
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
D7 | D6 | D5 | D4 | BL | EN | RW | RS
:param address: The I2C address of your LCD.
"""
self.address = address
self._backlight_pin_state = LCD_BACKLIGHT
self.i2c = i2c
self.i2c_device = I2CDevice(self.i2c, self.address)
self.data_buffer = bytearray(1)
def deinit(self):
self.i2c.deinit()
@property
def data_bus_mode(self):
return LCD_4BITMODE
@property
def backlight(self):
return self._backlight_pin_state == LCD_BACKLIGHT
@backlight.setter
def backlight(self, value):
self._backlight_pin_state = self._BACKLIGHT_VALUES[value]
with self.i2c_device:
self._i2c_write(self._backlight_pin_state)
# Low level commands
def send(self, value, rs_mode):
"""Send the specified value to the display in 4-bit nibbles.
The rs_mode is either ``_RS_DATA`` or ``_RS_INSTRUCTION``."""
self._write4bits(rs_mode | (value & 0xF0) | self._backlight_pin_state)
self._write4bits(rs_mode | ((value << 4) & 0xF0) | self._backlight_pin_state)
def _write4bits(self, value):
"""Pulse the `enable` flag to process value."""
with self.i2c_device:
self._i2c_write(value & ~PIN_ENABLE)
# This 1us delay is probably unnecessary, given the time needed
# to execute the statements.
microcontroller.delay_us(1)
self._i2c_write(value | PIN_ENABLE)
microcontroller.delay_us(1)
self._i2c_write(value & ~PIN_ENABLE)
# Wait for command to complete.
microcontroller.delay_us(100)
def _i2c_write(self, value):
self.data_buffer[0] = value
self.i2c_device.write(self.data_buffer)

289
lib/lcd/lcd.py Normal file
View File

@ -0,0 +1,289 @@
# Copyright (C) 2017 Dan Halbert
# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import time
from micropython import const
# Commands
_LCD_CLEARDISPLAY = const(0x01)
_LCD_RETURNHOME = const(0x02)
_LCD_ENTRYMODESET = const(0x04)
_LCD_DISPLAYCONTROL = const(0x08)
_LCD_CURSORSHIFT = const(0x10)
_LCD_FUNCTIONSET = const(0x20)
_LCD_SETCGRAMADDR = const(0x40)
_LCD_SETDDRAMADDR = const(0x80)
# Flags for display entry mode
_LCD_ENTRYRIGHT = const(0x00)
_LCD_ENTRYLEFT = const(0x02)
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
# Flags for display on/off control
_LCD_DISPLAYON = const(0x04)
_LCD_DISPLAYOFF = const(0x00)
_LCD_CURSORON = const(0x02)
_LCD_CURSOROFF = const(0x00)
_LCD_BLINKON = const(0x01)
_LCD_BLINKOFF = const(0x00)
# Flags for display/cursor shift
_LCD_DISPLAYMOVE = const(0x08)
_LCD_CURSORMOVE = const(0x00)
_LCD_MOVERIGHT = const(0x04)
_LCD_MOVELEFT = const(0x00)
# Flags for function set
_LCD_8BITMODE = const(0x10)
LCD_4BITMODE = const(0x00)
_LCD_2LINE = const(0x08)
_LCD_1LINE = const(0x00)
_LCD_5x10DOTS = const(0x04)
_LCD_5x8DOTS = const(0x00)
# Flags for backlight control
LCD_BACKLIGHT = const(0x08)
LCD_NOBACKLIGHT = const(0x00)
# Flags for RS pin modes
_RS_INSTRUCTION = const(0x00)
_RS_DATA = const(0x01)
# Pin bitmasks
PIN_ENABLE = const(0x4)
PIN_READ_WRITE = const(0x2)
PIN_REGISTER_SELECT = const(0x1)
class CursorMode:
HIDE = const(_LCD_CURSOROFF | _LCD_BLINKOFF)
LINE = const(_LCD_CURSORON | _LCD_BLINKOFF)
BLINK = const(_LCD_CURSOROFF | _LCD_BLINKON)
MICROSECOND = 1e-6
MILLISECOND = 1e-3
class LCD(object):
def __init__(self, interface, num_cols=20, num_rows=4, char_height=8):
"""
Character LCD controller.
:param interface: Communication interface, such as I2CInterface
:param num_rows: Number of display rows (usually 1, 2 or 4). Default: 4.
:param num_cols: Number of columns per row (usually 16 or 20). Default 20.
:param char_height: Some 1 line displays allow a font height of 10px.
Allowed: 8 or 10. Default: 8.
"""
self.interface = interface
if char_height not in (8, 10):
raise ValueError('The ``char_height`` argument should be either 8 or 10.')
self.char_height = char_height
self.num_rows = num_rows
self.num_cols = num_cols
# get row addresses (varies based on display size)
self._row_offsets = (0x00, 0x40, self.num_cols, 0x40 + self.num_cols)
# Setup initial display configuration
displayfunction = self.interface.data_bus_mode | _LCD_5x8DOTS
if self.num_rows == 1:
displayfunction |= _LCD_1LINE
elif self.num_rows in (2, 4):
# LCD only uses two lines on 4 row displays
displayfunction |= _LCD_2LINE
if self.char_height == 10:
# For some 1 line displays you can select a 10px font.
displayfunction |= _LCD_5x10DOTS
# Choose 4 or 8 bit mode
self.command(0x03)
time.sleep(4.5*MILLISECOND)
self.command(0x03)
time.sleep(4.5*MILLISECOND)
self.command(0x03)
if self.interface.data_bus_mode == LCD_4BITMODE:
# Hitachi manual page 46
time.sleep(100*MICROSECOND)
self.command(0x02)
elif self.interface.data_bus_mode == _LCD_8BITMODE:
# Hitachi manual page 45
self.command(0x30)
time.sleep(4.5*MILLISECOND)
self.command(0x30)
time.sleep(100*MICROSECOND)
self.command(0x30)
else:
raise ValueError('Invalid data bus mode: {}'.format(self.interface.data_bus_mode))
# Write configuration to display
self.command(_LCD_FUNCTIONSET | displayfunction)
time.sleep(50*MICROSECOND)
# Configure entry mode. Define internal fields.
self.command(_LCD_ENTRYMODESET | _LCD_ENTRYLEFT)
time.sleep(50*MICROSECOND)
# Configure display mode. Define internal fields.
self._display_mode = _LCD_DISPLAYON
self._cursor_mode = CursorMode.HIDE
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
time.sleep(50*MICROSECOND)
self.clear()
def close(self):
self.interface.deinit()
def set_backlight(self, value):
self.interface.backlight = value
def set_display_enabled(self, value):
self._display_mode = _LCD_DISPLAYON if value else _LCD_DISPLAYOFF
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
time.sleep(50*MICROSECOND)
def set_cursor_mode(self, value):
self._cursor_mode = value
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
time.sleep(50*MICROSECOND)
def cursor_pos(self):
"""The cursor position as a 2-tuple (row, col)."""
return (self._row, self._col)
def set_cursor_pos(self, row, col):
if not (0 <= row < self.num_rows):
raise ValueError('row should be in range 0-{}'.format(self.num_rows - 1))
if not (0 <= col < self.num_cols):
raise ValueError('col should be in range 0-{}'.format(self.num_cols - 1))
self._row = row
self._col = col
self.command(_LCD_SETDDRAMADDR | self._row_offsets[row] + col)
time.sleep(50*MICROSECOND)
def print(self, string):
"""
Write the specified unicode string to the display.
A newline ('\n') will advance to the left side of the next row.
Lines that are too long automatically continue on next line.
Only characters with an ``ord()`` value between 0 and 255 are currently
supported.
"""
for char in string:
if char == '\n':
# Advance to next row, at left side. Wrap around to top row if at bottom.
self.set_cursor_pos((self._row + 1) % self.num_rows, 0)
else:
self.write(ord(char))
def clear(self):
"""Overwrite display with blank characters and reset cursor position."""
self.command(_LCD_CLEARDISPLAY)
time.sleep(2*MILLISECOND)
self.home()
def home(self):
"""Set cursor to initial position and reset any shifting."""
self.command(_LCD_RETURNHOME)
self._row = 0
self._col = 0
time.sleep(2*MILLISECOND)
def shift_display(self, amount):
"""Shift the display. Use negative amounts to shift left and positive
amounts to shift right."""
if amount == 0:
return
direction = _LCD_MOVERIGHT if amount > 0 else _LCD_MOVELEFT
for i in range(abs(amount)):
self.command(_LCD_CURSORSHIFT | _LCD_DISPLAYMOVE | direction)
time.sleep(50*MICROSECOND)
def create_char(self, location, bitmap):
"""Create a new character.
The HD44780 supports up to 8 custom characters (location 0-7).
:param location: The place in memory where the character is stored.
Values need to be integers between 0 and 7.
:type location: int
:param bitmap: The bitmap containing the character. This should be a
bytearray of 8 numbers, each representing a 5 pixel row.
:type bitmap: bytearray
:raises AssertionError: Raised when an invalid location is passed in or
when bitmap has an incorrect size.
Example:
.. sourcecode:: python
>>> smiley = bytearray(
... 0b00000,
... 0b01010,
... 0b01010,
... 0b00000,
... 0b10001,
... 0b10001,
... 0b01110,
... 0b00000,
... )
>>> lcd.create_char(0, smiley)
"""
if not (0 <= location <= 7):
raise ValueError('Only locations 0-7 are valid.')
if len(bitmap) != 8:
raise ValueError('Bitmap should have exactly 8 rows.')
# Store previous position
save_row = self._row
save_col = self._col
# Write character to CGRAM
self.command(_LCD_SETCGRAMADDR | location << 3)
for row in bitmap:
self.interface.send(row, _RS_DATA)
# Restore cursor pos
self.set_cursor_pos(save_row, save_col)
def command(self, value):
"""Send a raw command to the LCD."""
self.interface.send(value, _RS_INSTRUCTION)
def write(self, value):
"""Write a raw character byte to the LCD."""
self.interface.send(value, _RS_DATA)
if self._col < self.num_cols - 1:
# Char was placed on current line. No need to reposition cursor.
self._col += 1
else:
# At end of line: go to left side next row. Wrap around to first row if on last row.
self._row = (self._row + 1) % self.num_rows
self._col = 0
self.set_cursor_pos(self._row, self._col)

1
lib/rgb1602/__init__.py Normal file
View File

@ -0,0 +1 @@
from rgb1602.display import Screen

164
lib/rgb1602/colours.py Normal file
View File

@ -0,0 +1,164 @@
CSS_COLOURS: dict[str, tuple[int, int, int]] = {
"aliceblue": (240, 248, 255),
"antiquewhite": (250, 235, 215),
"aqua": (0, 255, 255),
"aquamarine": (127, 255, 212),
"azure": (240, 255, 255),
"beige": (245, 245, 220),
"bisque": (255, 228, 196),
"black": (0, 0, 0),
"blanchedalmond": (255, 235, 205),
"blue": (0, 0, 255),
"blueviolet": (138, 43, 226),
"brown": (165, 42, 42),
"burlywood": (222, 184, 135),
"cadetblue": (95, 158, 160),
"chartreuse": (127, 255, 0),
"chocolate": (210, 105, 30),
"coral": (255, 127, 80),
"cornflowerblue": (100, 149, 237),
"cornsilk": (255, 248, 220),
"crimson": (220, 20, 60),
"cyan": (0, 255, 255),
"darkblue": (0, 0, 139),
"darkcyan": (0, 139, 139),
"darkgoldenrod": (184, 134, 11),
"darkgray": (169, 169, 169),
"darkgreen": (0, 100, 0),
"darkgrey": (169, 169, 169),
"darkkhaki": (189, 183, 107),
"darkmagenta": (139, 0, 139),
"darkolivegreen": (85, 107, 47),
"darkorange": (255, 140, 0),
"darkorchid": (153, 50, 204),
"darkred": (139, 0, 0),
"darksalmon": (233, 150, 122),
"darkseagreen": (143, 188, 143),
"darkslateblue": (72, 61, 139),
"darkslategray": (47, 79, 79),
"darkslategrey": (47, 79, 79),
"darkturquoise": (0, 206, 209),
"darkviolet": (148, 0, 211),
"deeppink": (255, 20, 147),
"deepskyblue": (0, 191, 255),
"dimgray": (105, 105, 105),
"dimgrey": (105, 105, 105),
"dodgerblue": (30, 144, 255),
"firebrick": (178, 34, 34),
"floralwhite": (255, 250, 240),
"forestgreen": (34, 139, 34),
"fuchsia": (255, 0, 255),
"gainsboro": (220, 220, 220),
"ghostwhite": (248, 248, 255),
"gold": (255, 215, 0),
"goldenrod": (218, 165, 32),
"gray": (128, 128, 128),
"green": (0, 128, 0),
"greenyellow": (173, 255, 47),
"grey": (128, 128, 128),
"honeydew": (240, 255, 240),
"hotpink": (255, 105, 180),
"indianred": (205, 92, 92),
"indigo": (75, 0, 130),
"ivory": (255, 255, 240),
"khaki": (240, 230, 140),
"lavender": (230, 230, 250),
"lavenderblush": (255, 240, 245),
"lawngreen": (124, 252, 0),
"lemonchiffon": (255, 250, 205),
"lightblue": (173, 216, 230),
"lightcoral": (240, 128, 128),
"lightcyan": (224, 255, 255),
"lightgoldenrodyellow": (250, 250, 210),
"lightgray": (211, 211, 211),
"lightgreen": (144, 238, 144),
"lightgrey": (211, 211, 211),
"lightpink": (255, 182, 193),
"lightsalmon": (255, 160, 122),
"lightseagreen": (32, 178, 170),
"lightskyblue": (135, 206, 250),
"lightslategray": (119, 136, 153),
"lightslategrey": (119, 136, 153),
"lightsteelblue": (176, 196, 222),
"lightyellow": (255, 255, 224),
"lime": (0, 255, 0),
"limegreen": (50, 205, 50),
"linen": (250, 240, 230),
"magenta": (255, 0, 255),
"maroon": (128, 0, 0),
"mediumaquamarine": (102, 205, 170),
"mediumblue": (0, 0, 205),
"mediumorchid": (186, 85, 211),
"mediumpurple": (147, 112, 219),
"mediumseagreen": (60, 179, 113),
"mediumslateblue": (123, 104, 238),
"mediumspringgreen": (0, 250, 154),
"mediumturquoise": (72, 209, 204),
"mediumvioletred": (199, 21, 133),
"midnightblue": (25, 25, 112),
"mintcream": (245, 255, 250),
"mistyrose": (255, 228, 225),
"moccasin": (255, 228, 181),
"navajowhite": (255, 222, 173),
"navy": (0, 0, 128),
"oldlace": (253, 245, 230),
"olive": (128, 128, 0),
"olivedrab": (107, 142, 35),
"orange": (255, 165, 0),
"orangered": (255, 69, 0),
"orchid": (218, 112, 214),
"palegoldenrod": (238, 232, 170),
"palegreen": (152, 251, 152),
"paleturquoise": (175, 238, 238),
"palevioletred": (219, 112, 147),
"papayawhip": (255, 239, 213),
"peachpuff": (255, 218, 185),
"peru": (205, 133, 63),
"pink": (255, 192, 203),
"plum": (221, 160, 221),
"powderblue": (176, 224, 230),
"purple": (128, 0, 128),
"rebeccapurple": (102, 51, 153),
"red": (255, 0, 0),
"rosybrown": (188, 143, 143),
"royalblue": (65, 105, 225),
"saddlebrown": (139, 69, 19),
"salmon": (250, 128, 114),
"sandybrown": (244, 164, 96),
"seagreen": (46, 139, 87),
"seashell": (255, 245, 238),
"sienna": (160, 82, 45),
"silver": (192, 192, 192),
"skyblue": (135, 206, 235),
"slateblue": (106, 90, 205),
"slategray": (112, 128, 144),
"slategrey": (112, 128, 144),
"snow": (255, 250, 250),
"springgreen": (0, 255, 127),
"steelblue": (70, 130, 180),
"tan": (210, 180, 140),
"teal": (0, 128, 128),
"thistle": (216, 191, 216),
"tomato": (255, 99, 71),
"turquoise": (64, 224, 208),
"violet": (238, 130, 238),
"wheat": (245, 222, 179),
"white": (255, 255, 255),
"whitesmoke": (245, 245, 245),
"yellow": (255, 255, 0),
"yellowgreen": (154, 205, 50),
}
CSS_COLORS = CSS_COLOURS
WAVESHARE_COLOURS = {
"Deep violet": (148, 0, 110),
"Purple": (255, 0, 255),
"Blue and white": (144, 249, 15),
"Light blue": (0, 128, 60),
"Yellow": (255, 209, 0),
"Ghost white": (248, 248, 60),
"Dark blue": (80, 80, 145),
"Red": (255, 0, 0),
"Cyan": (0, 255, 0),
}
WAVESHARE_COLORS = WAVESHARE_COLOURS

307
lib/rgb1602/display.py Normal file
View File

@ -0,0 +1,307 @@
# This file converted from MicroPython to CircuitPython
# by robjwells. Original copyright Waveshare.
from time import sleep
from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_register.i2c_struct import UnaryStruct
from busio import I2C
from microcontroller import Pin
from rgb1602.colours import CSS_COLOURS
class Constants:
# Device I2C Addresses
LCD_ADDRESS = 0x7C >> 1
RGB_ADDRESS = 0x3e >> 1
# fmt: off
# CGRAM and DDRAM commands but also their memory addresses
LCD_COMMAND_REG = 0x80
LCD_SETDDRAMADDR = 0x80 # 0b1_______ Display Data RAM
LCD_SETCGRAMADDR = 0x40 # 0b_1______ Character Generator RAM
LCD_DATA_REG = 0x40
# RGB registers
REG_RED = 0x04 # 0b_1__ pwm2
REG_GREEN = 0x03 # 0b__11 pwm1
REG_BLUE = 0x02 # 0b__1_ pwm0
REG_MODE1 = 0x00 # 0b____
REG_MODE2 = 0x01 # 0b___1
REG_OUTPUT = 0x08 # 0b1___
# Commands -- bits of an 8-bit word
LCD_CLEARDISPLAY = 0x01 # 0b_______1
LCD_RETURNHOME = 0x02 # 0b______1_
LCD_ENTRYMODESET = 0x04 # 0b_____1__
# Used with bits I/D SH:
# I/D: 0x02 for entry left, 0x00 for entry right
# SH: 0x01 for shift increment, 0x00 for decrement
# See "flags for display entry mode"
LCD_DISPLAYCONTROL = 0x08 # 0b____1___
# Used with bits DCB:
# D: display on/off,
# C: cursor on/off,
# B: blink cursor on/off
# These are listed below as "flags for display on/off control"
LCD_CURSORSHIFT = 0x10 # 0b___1____
# Cursor or Display Shift
# Uses bits S/C R/L - -:
# S/C: 0x08 for screen or 0x00 for cursor
# R/L: 0x04 for right or 0x00 for left
LCD_FUNCTIONSET = 0x20 # 0b__1_____
# Sets number of display lines, and display font type.
# The documentation doesn't mention 8/4 bit mode.
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00 # 0b00
LCD_ENTRYLEFT = 0x02 # 0b10
LCD_ENTRYSHIFTINCREMENT = 0x01 # 0b01
LCD_ENTRYSHIFTDECREMENT = 0x00 # 0b00
# flags for display on/off control
LCD_DISPLAYON = 0x04 # 0b1__
LCD_CURSORON = 0x02 # 0b_1_
LCD_BLINKON = 0x01 # 0b__1
LCD_DISPLAYOFF = 0x00 # 0b000
LCD_CURSOROFF = 0x00 # 0b000
LCD_BLINKOFF = 0x00 # 0b000
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08 # 0b1000
LCD_CURSORMOVE = 0x00 # 0b0000
LCD_MOVERIGHT = 0x04 # 0b0100
LCD_MOVELEFT = 0x00 # 0b0000
# flags for function set
# I think the modes relate the to the number of bits
# sent down the wire at a time, _not_ the colour
# depth (as I thought originally).
LCD_8BITMODE = 0x10 # 0b10000
LCD_4BITMODE = 0x00 # 0b00000
# Number of lines on the display
LCD_2LINE = 0x08 # 0b01000
LCD_1LINE = 0x00 # 0b00000
LCD_5x8DOTS = 0x00 # 0b00000
# fmt: on
class LCDControl:
def __init__(self, i2c: I2CDevice):
self.i2c_device = i2c # Required by UnaryStruct
command_register = UnaryStruct(Constants.LCD_COMMAND_REG, "<B")
data_register = UnaryStruct(Constants.LCD_DATA_REG, "<B")
class RGBControl:
def __init__(self, i2c: I2CDevice) -> None:
self.i2c_device = i2c
REG_RED = UnaryStruct(Constants.REG_RED, "<B")
REG_GREEN = UnaryStruct(Constants.REG_GREEN, "<B")
REG_BLUE = UnaryStruct(Constants.REG_BLUE, "<B")
REG_MODE1 = UnaryStruct(Constants.REG_MODE1, "<B")
REG_MODE2 = UnaryStruct(Constants.REG_MODE2, "<B")
REG_OUTPUT = UnaryStruct(Constants.REG_OUTPUT, "<B")
class Screen:
# Set dimensions as class variables.
# Hint is in the module name (LCD1602)!
COLS = 16
ROWS = 2
current_colour: tuple[int, int, int]
_i2c: I2C
_lcd: LCDControl
_rgb: RGBControl
def __init__(self, i2c_bus: I2C):
self._i2c = i2c_bus
self._lcd = LCDControl(I2CDevice(self._i2c, Constants.LCD_ADDRESS))
self._rgb = RGBControl(I2CDevice(self._i2c, Constants.RGB_ADDRESS))
self._reset_display()
def _reset_display(self):
"""Initialise the display to its standard settings.
It is unclear to me (rjw) why some of these are necessary, as
there seems to be no difference in removing some of the below.
*However* I have not removed what remains because it wasn't
*obviously unnecessary*, unlike the now-removed lines.
"""
# Send function set command sequence
show_function = (
Constants.LCD_4BITMODE | Constants.LCD_2LINE | Constants.LCD_5x8DOTS
)
self._command(Constants.LCD_FUNCTIONSET | show_function)
sleep(0.05)
# turn the display on with no cursor or blinking default
show_control = (
Constants.LCD_DISPLAYON | Constants.LCD_CURSOROFF | Constants.LCD_BLINKOFF
)
self._command(Constants.LCD_DISPLAYCONTROL | show_control)
self.clear()
# Initialize to default text direction (for romance languages)
self._showmode = Constants.LCD_ENTRYLEFT | Constants.LCD_ENTRYSHIFTDECREMENT
self._command(Constants.LCD_ENTRYMODESET | self._showmode)
# backlight init
self._set_rgb_register("REG_MODE1", 0)
# set LEDs controllable by both PWM and GRPPWM registers
self._set_rgb_register("REG_OUTPUT", 0xFF)
# set MODE2 values
# 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode)
self._set_rgb_register("REG_MODE2", 0x20)
self.set_white()
def _command(self, cmd: int):
assert 0 <= cmd <= 255, f"Command {cmd} out of range."
self._lcd.command_register = cmd
def _write_byte(self, data: int) -> None:
assert 0 <= data <= 255, f"Command {data} out of range."
self._lcd.data_register = data
def _set_rgb_register(self, reg: str, data: int) -> None:
assert reg in (
"REG_RED",
"REG_BLUE",
"REG_GREEN",
"REG_MODE1",
"REG_MODE2",
"REG_OUTPUT",
), f"Register {reg} is not a known register."
assert 0 <= data <= 255, f"Data {data} is out of range."
setattr(self._rgb, reg, data)
def _set_rgb_mode(self, mode: int, value: int) -> None:
assert 0 <= value <= 0xFF, "Value not in range."
if mode == 1:
self._set_rgb_register("REG_MODE1", value)
elif mode == 2:
self._set_rgb_register("REG_MODE2", value)
else:
raise ValueError(f"Unknown mode: {repr(mode)}")
def set_rgb(self, r: int, g: int, b: int):
assert 0 <= r <= 255, f"Red value {r} out of range."
assert 0 <= g <= 255, f"Green value {g} out of range."
assert 0 <= b <= 255, f"Blue value {b} out of range."
self._set_rgb_register("REG_RED", r)
self._set_rgb_register("REG_GREEN", g)
self._set_rgb_register("REG_BLUE", b)
self.current_colour = (r, g, b)
def position_cursor(self, *, col: int, row: int):
assert (
0 <= col < self.COLS
), f"Column {col} is out of bounds (max {self.COLS - 1})."
assert (
0 <= row < self.ROWS
), f"Row {row} is out of bounds (max {self.ROWS - 1})."
if row == 0:
col |= 0x80
else:
col |= 0xC0
assert self._i2c.try_lock(), "Could not lock"
self._i2c.writeto(
Constants.LCD_ADDRESS, bytearray([Constants.LCD_SETDDRAMADDR, col])
)
self._i2c.unlock()
def clear(self):
self._command(Constants.LCD_CLEARDISPLAY)
sleep(0.002)
def write_bytes(self, arg: bytes):
for byte in arg:
self._write_byte(byte)
def write_at_position(self, text: str | bytes, *, col: int, row: int) -> None:
self.position_cursor(col=col, row=row)
self.write_bytes(self._ensure_bytes(text))
@staticmethod
def _ensure_bytes(s: str | bytes) -> bytes:
if isinstance(s, bytes):
return s
# Not JIS X 0213 but close enough if youre careful.
return bytes(s, "jisx0213")
def update(
self, first_line: str | bytes, second_line: str | bytes | None = None
) -> None:
first = self._ensure_bytes(first_line)
self.clear()
self.write_bytes(first[: self.COLS])
if second_line is not None:
self.position_cursor(col=0, row=1)
second = self._ensure_bytes(second_line)
self.write_bytes(second[: self.COLS])
def set_white(self) -> None:
self.set_css_colour("white")
def set_css_colour(self, colour_name: str) -> None:
self.set_rgb(*CSS_COLOURS[colour_name])
def set_css_color(self, color_name: str) -> None:
self.set_css_colour(color_name)
def set_backlight_power(self, on: bool) -> None:
data = 0xFF if on else 0x00
self._set_rgb_register("REG_OUTPUT", data)
@staticmethod
def special_char(c: str) -> bytes:
if c == "\\":
raise ValueError("\\ (backslash) is not in the character set.")
elif ord(c) < ord("}"):
# Everything matches ASCII up to }, except for \ -> ¥.
return c.encode("ascii")
chars = {
"": b"\x7E",
"": b"\x7F",
"": b"\xA5",
"": b"\xDB",
"°": b"\xDF",
"alpha": b"\xE0",
"beta": b"\xE2",
"epsilon": b"\xE3",
"mu": b"\xE4",
"sigma": b"\xE5",
"rho": b"\xE6",
"": b"\xE8",
"theta": b"\xF2",
"omega": b"\xF4",
"SIGMA": b"\xF6",
"pi": b"\xF7",
"÷": b"\xFD",
"block": b"\xFF",
}
try:
return chars[c]
except KeyError:
raise ValueError(f"Character {repr(c)} is not a registered special character.")

45
lib/rgb1602/examples.py Normal file
View File

@ -0,0 +1,45 @@
from time import sleep
from rgb1602.colours import CSS_COLOURS, WAVESHARE_COLOURS
from rgb1602.display import Screen
def _show_colours(
screen: Screen,
delay: int,
colours: dict[str, tuple[int, int, int]],
colour_set_name: str,
) -> None:
original_rgb = screen.current_colour
for colour_name, rgb in sorted(colours.items()):
screen.set_rgb(*rgb)
screen.update(colour_set_name, colour_name)
sleep(delay)
screen.set_rgb(*original_rgb)
def show_css_colours(screen: Screen, delay: int = 2) -> None:
_show_colours(screen, delay, CSS_COLOURS, "CSS named colour")
def show_waveshare_colours(screen: Screen, delay: int = 2) -> None:
_show_colours(screen, delay, WAVESHARE_COLOURS, "Waveshare")
def show_discoloration_sample(screen: Screen) -> None:
from math import sin
screen.update(f"Waveshare", "Hello, world!")
t = 0
while True:
r = int((abs(sin(3.14 * t / 180))) * 255)
g = int((abs(sin(3.14 * (t + 60) / 180))) * 255)
b = int((abs(sin(3.14 * (t + 120) / 180))) * 255)
t = (t + 3) % 360
screen.set_rgb(r, g, b)
screen.write_at_position(
str(t).encode() + screen.special_char("°") + b" ", col=10, row=0
)
sleep(0.3)

234
lib/waveshare_lcd1602.py Normal file
View File

@ -0,0 +1,234 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) Waveshare
# SPDX-FileCopyrightText: Copyright (c) 2022 Neradoc
#
# SPDX-License-Identifier: MIT
#
# In order to keep basic compatibility with the orifinal library, ignore "bad" names.
# pylint: disable=invalid-name
"""
`waveshare_lcd1602`
================================================================================
Drive for Waveshare's I2C character display LCD1602.
A port of Waveshare's RGB1602 Micropython library.
* Author(s): Neradoc
Implementation Notes
--------------------
**Hardware:**
* `Waveshare LCD1602 RGB Module <https://www.waveshare.com/wiki/LCD1602_RGB_Module>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""
import time
from adafruit_bus_device.i2c_device import I2CDevice
try:
from typing import Union
import busio
except ImportError:
pass
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/Neradoc/Circuitpython_Waveshare_LCD1602.git"
# Device I2C Arress
LCD_ADDRESS = 0x7C >> 1
RGB_ADDRESS = 0xC0 >> 1
# color define
REG_RED = 0x04
REG_GREEN = 0x03
REG_BLUE = 0x02
REG_MODE1 = 0x00
REG_MODE2 = 0x01
REG_OUTPUT = 0x08
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5X8DOTS = 0x00
class LCD1602:
"""
Setup a new RGB LCD1602 display
:param busio.I2C i2c: I2C bus object to use.
:param int columns: The number of columns on the display.
:param int rows: The number of rows on the display.
"""
def __init__(self, i2c: busio.I2C, columns: int, rows: int):
self.lcd_device = I2CDevice(i2c, LCD_ADDRESS)
#self.rgb_device = I2CDevice(i2c, RGB_ADDRESS)
self._row = rows
self._col = columns
self._showfunction = LCD_4BITMODE | LCD_1LINE | LCD_5X8DOTS
self.begin(self._row, self._col)
def command(self, cmd: int):
"""
Send a command.
:param int cmd: The command code.
"""
with self.lcd_device:
self.lcd_device.write(bytes([0x80]) + chr(cmd))
def write(self, data: int):
"""
Write a data byte.
:param int data: The data byte to write.
"""
with self.lcd_device:
self.lcd_device.write(bytes([0x40]) + chr(data))
def setReg(self, reg, data):
"""
Set the value of a register.
:param int reg: The register to write to.
:param int data: The data byte to write.
"""
#with self.rgb_device:
# self.rgb_device.write(bytes([reg]) + chr(data))
def setRGB(self, r, g, b):
"""
Set the color of the RGB backlight.
:param int r: Red byte.
:param int g: Green byte.
:param int b: Blue byte.
"""
self.setReg(REG_RED, r)
self.setReg(REG_GREEN, g)
self.setReg(REG_BLUE, b)
def setCursor(self, col, row):
"""
Place the cursor on the display.
:param int col: The column.
:param int row: The row.
"""
if row == 0:
col |= 0x80
else:
col |= 0xC0
with self.lcd_device:
self.lcd_device.write(bytearray([0x80, col]))
def clear(self):
"""Clear the display."""
self.command(LCD_CLEARDISPLAY)
time.sleep(0.002)
def printout(self, arg: Union[str, int]):
"""
Print a string to the display. Ints are converted to strings.
:param str|int arg: The string or int to printout.
"""
if isinstance(arg, int):
arg = str(arg)
for x in bytearray(arg, "utf-8"):
self.write(x)
def display(self):
"""Turn on the display."""
self._showcontrol |= LCD_DISPLAYON
self.command(LCD_DISPLAYCONTROL | self._showcontrol)
def begin(self, columns: int, rows: int): # pylint: disable=unused-argument
"""
Initial configuration, called from init.
:param int columns: The number of columns on the display.
:param int rows: The number of rows on the display.
"""
if rows > 1:
self._showfunction |= LCD_2LINE
self._numlines = rows
self._currline = 0
time.sleep(0.05)
# Send function set command sequence
self.command(LCD_FUNCTIONSET | self._showfunction)
# delayMicroseconds(4500); # wait more than 4.1ms
time.sleep(0.005)
# second try
self.command(LCD_FUNCTIONSET | self._showfunction)
# delayMicroseconds(150);
time.sleep(0.005)
# third go
self.command(LCD_FUNCTIONSET | self._showfunction)
# finally, set # lines, font size, etc.
self.command(LCD_FUNCTIONSET | self._showfunction)
# turn the display on with no cursor or blinking default
self._showcontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF
self.display()
# clear it off
self.clear()
# Initialize to default text direction (for romance languages)
self._showmode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT
# set the entry mode
self.command(LCD_ENTRYMODESET | self._showmode)
# backlight init
self.setReg(REG_MODE1, 0)
# set LEDs controllable by both PWM and GRPPWM registers
self.setReg(REG_OUTPUT, 0xFF)
# set MODE2 values
# 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode)
self.setReg(REG_MODE2, 0x20)
self.setColorWhite()
def setColorWhite(self):
"""Set the color of the RGB backlight to white."""
self.setRGB(255, 255, 255)

194
macros/archinstall.mcr Normal file
View File

@ -0,0 +1,194 @@
# First Boot
"loadkeys uk"
WAIT 1
enter
WAIT 1
"archinstall"
WAIT 1
enter
WAIT 10
# Locales
downarrow
enter
WAIT 1
enter
forwardslash
"uk"
enter
WAIT 1
downarrow
enter
forwardslash
"en_gb."
downarrow
enter
WAIT 1
downarrow
downarrow
enter
# Mirrors
downarrow
enter
enter
forwardslash
"kin"
enter
WAIT 5
downarrow
downarrow
downarrow
downarrow
enter
WAIT 1
# Partitions
# EXT4 Main Drive
downarrow
enter
enter
enter
space
enter
downarrow
enter
# Encryption
downarrow
downarrow
enter
enter
enter
downarrow
enter
LCD_SHOW "Password? (5s)"
WAIT 5
enter
LCD_SHOW "Password? (5s)"
WAIT 5
enter
downarrow
enter
space
enter
downarrow
downarrow
enter
downarrow
enter
# Bootloader
downarrow
downarrow
enter
WAIT 1
# Pick GRUB
forwardslash
"grub"
enter
# Hostname
downarrow
enter
WAIT 1
# Clear out pre-filled hostname
backspace
backspace
backspace
backspace
backspace
backspace
backspace
backspace
backspace
backspace
# Entering new hostname
LCD_SHOW "Hostname? (5s)"
WAIT 5
enter
# Users
downarrow
downarrow
enter
enter
# Prompt for username + password
LCD_SHOW "Username? (5s)"
WAIT 5
enter
LCD_SHOW "Password? (5s)"
WAIT 5
enter
LCD_SHOW "Password? (5s)"
WAIT 5
enter
enter
downarrow
downarrow
enter
# Profile
downarrow
enter
enter
forwardslash
"Min"
enter
WAIT 1
downarrow
enter
# Audio servers
downarrow
enter
downarrow
downarrow
enter
# Networking
downarrow
downarrow
enter
enter
# Time and Date
downarrow
downarrow
enter
forwardslash
"london"
enter
WAIT 1
downarrow
enter
enter
# Install
downarrow
downarrow
enter
enter

0
macros/syntax.mcr Normal file
View File

59
macros/test.mcr Normal file
View File

@ -0,0 +1,59 @@
LCD_SHOW "Hi"
# test comment
WAIT 3
HOLD
super
"d"
RELEASE
"text editor"
enter
HOLD
ctrl
"n"
RELEASE
tab
forwardslash
space
backslash
HOLD
shift
"a"
RELEASE
enter
capslock
"caps"
capslock
enter
"lowercase"
backspace
enter
"sentence longer than 16 chars..."

0
settings.toml Normal file
View File