feat: Implement OLED display support and custom icons for 128x32 displays
- Added OLED functionality in keymap.c with custom rendering for layers and modifiers. - Created a Python script to generate simple icons for OLED displays. - Introduced a new rules.mk file to enable OLED features for the keymap. - Developed an OLED font helper script for visualizing and designing custom graphics. - Redesigned OLED layout to fit 128x32 displays, optimizing space for logos and layer indicators. - Implemented flow tap functionality in flow_tap.c for enhanced key responsiveness.
This commit is contained in:
parent
f3afe70c10
commit
ac0b03a50c
15 changed files with 1300 additions and 17 deletions
168
oled_font_helper.py
Normal file
168
oled_font_helper.py
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
OLED Font Helper - Visualize and design custom graphics for QMK OLED displays
|
||||
For 128x32 displays (4 rows × 21 characters, each character is 6x8 pixels)
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def parse_font_file(filename):
|
||||
"""Parse the glcdfont.c file and extract character definitions"""
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract the font array data
|
||||
font_match = re.search(r'const unsigned char font\[\] PROGMEM = \{(.*?)\};', content, re.DOTALL)
|
||||
if not font_match:
|
||||
print("ERROR: Could not find font array in file")
|
||||
return None
|
||||
|
||||
font_data = font_match.group(1)
|
||||
|
||||
# Parse hex values
|
||||
hex_values = re.findall(r'0x[0-9A-Fa-f]{2}', font_data)
|
||||
|
||||
# Each character is 6 bytes
|
||||
characters = []
|
||||
for i in range(0, len(hex_values), 6):
|
||||
if i + 6 <= len(hex_values):
|
||||
char_bytes = [int(h, 16) for h in hex_values[i:i+6]]
|
||||
characters.append(char_bytes)
|
||||
|
||||
return characters
|
||||
|
||||
def visualize_char(char_bytes, char_code):
|
||||
"""Visualize a single character as ASCII art"""
|
||||
print(f"\n=== Character 0x{char_code:02X} ({char_code}) ===")
|
||||
|
||||
# Each byte represents 8 vertical pixels
|
||||
# We have 6 bytes (6 columns of pixels)
|
||||
for row in range(8):
|
||||
line = ""
|
||||
for col in range(6):
|
||||
byte = char_bytes[col]
|
||||
# Check if bit at position 'row' is set
|
||||
if byte & (1 << row):
|
||||
line += "██"
|
||||
else:
|
||||
line += " "
|
||||
print(line)
|
||||
|
||||
def visualize_range(characters, start, end):
|
||||
"""Visualize a range of characters"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Visualizing characters 0x{start:02X} to 0x{end:02X}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
for i in range(start, min(end + 1, len(characters))):
|
||||
visualize_char(characters[i], i)
|
||||
|
||||
def show_oled_layout(characters, char_codes, title="OLED Display"):
|
||||
"""Show how characters will look when displayed together on OLED"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"{title}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# For 128x32 display, we can show characters side by side
|
||||
# Each character is 6 pixels wide, 8 pixels tall
|
||||
|
||||
# Find how many characters we have
|
||||
num_chars = len(char_codes)
|
||||
|
||||
# Display all 8 rows
|
||||
for row in range(8):
|
||||
line = ""
|
||||
for char_code in char_codes:
|
||||
if char_code >= len(characters):
|
||||
# Empty character
|
||||
line += " "
|
||||
else:
|
||||
char_bytes = characters[char_code]
|
||||
for col in range(6):
|
||||
byte = char_bytes[col]
|
||||
if byte & (1 << row):
|
||||
line += "█"
|
||||
else:
|
||||
line += " "
|
||||
print(line)
|
||||
|
||||
def main():
|
||||
font_file = "keyboards/fingerpunch/sweeeeep/keymaps/smathev/glcdfont.c"
|
||||
|
||||
print("="*60)
|
||||
print("QMK OLED Font Visualizer")
|
||||
print("="*60)
|
||||
|
||||
characters = parse_font_file(font_file)
|
||||
if not characters:
|
||||
return
|
||||
|
||||
print(f"\nFound {len(characters)} characters in font file")
|
||||
|
||||
# Show the logo (what render_logo displays)
|
||||
print("\n" + "="*60)
|
||||
print("CURRENT LOGO (render_logo)")
|
||||
print("="*60)
|
||||
logo_chars = [
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, # Row 1
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, # Row 2
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, # Row 3
|
||||
]
|
||||
show_oled_layout(characters, logo_chars, "Logo Graphics")
|
||||
print("\nFollowed by text: 'Gio*K'")
|
||||
|
||||
# Show layer indicators
|
||||
print("\n" + "="*60)
|
||||
print("DEFAULT LAYER INDICATOR")
|
||||
print("="*60)
|
||||
default_layer = [0x94, 0x95, 0x96, 0xb4, 0xb5, 0xb6, 0xd4, 0xd5, 0xd6]
|
||||
show_oled_layout(characters, default_layer, "Default Layer Icon")
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("RAISE/NAVIGATION LAYER INDICATOR")
|
||||
print("="*60)
|
||||
raise_layer = [0x97, 0x98, 0x99, 0xb7, 0xb8, 0xb9, 0xd7, 0xd8, 0xd9]
|
||||
show_oled_layout(characters, raise_layer, "Navigation Layer Icon")
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("LOWER/SYMBOLS LAYER INDICATOR")
|
||||
print("="*60)
|
||||
lower_layer = [0x9a, 0x9b, 0x9c, 0xba, 0xbb, 0xbc, 0xda, 0xdb, 0xdc]
|
||||
show_oled_layout(characters, lower_layer, "Symbols Layer Icon")
|
||||
|
||||
# Show modifier indicators
|
||||
print("\n" + "="*60)
|
||||
print("MODIFIER KEY INDICATORS")
|
||||
print("="*60)
|
||||
|
||||
print("\nGUI (Super/Windows) Key:")
|
||||
show_oled_layout(characters, [0x85, 0x86, 0xa5, 0xa6], "GUI Off")
|
||||
show_oled_layout(characters, [0x87, 0x88, 0xa7, 0xa8], "GUI On")
|
||||
|
||||
print("\nALT Key:")
|
||||
show_oled_layout(characters, [0x89, 0x8a, 0xa9, 0xaa], "ALT Off")
|
||||
show_oled_layout(characters, [0xcd, 0xce, 0xcf, 0xd0], "ALT On")
|
||||
|
||||
print("\nCTRL Key:")
|
||||
show_oled_layout(characters, [0x8d, 0x8e, 0xad, 0xae], "CTRL Off")
|
||||
show_oled_layout(characters, [0x8f, 0x90, 0xaf, 0xb0], "CTRL On")
|
||||
|
||||
print("\nSHIFT Key:")
|
||||
show_oled_layout(characters, [0x8b, 0x8c, 0xab, 0xac], "SHIFT Off")
|
||||
show_oled_layout(characters, [0xcd, 0xce, 0xcf, 0xd0], "SHIFT On")
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("\nNOTE: Your OLED is 128x32 (4 rows × 21 characters)")
|
||||
print("Each character is 6 pixels wide × 8 pixels tall")
|
||||
print("Total usable width: 126 pixels (21 chars × 6 pixels)")
|
||||
print("\nFor best results on 4 rows:")
|
||||
print("- Row 1: Logo + text (first line)")
|
||||
print("- Row 2: Layer indicator + modifiers (second line)")
|
||||
print("- Row 3: Additional info (third line)")
|
||||
print("- Row 4: WPM or other status (fourth line)")
|
||||
print("\nTo edit graphics, use: https://helixfonteditor.netlify.com/")
|
||||
print("Or manually edit the hex values in glcdfont.c")
|
||||
print("="*60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue