qmk_userspace/oled_font_helper.py
Smathev ac0b03a50c 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.
2025-10-08 13:57:24 +02:00

168 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()