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:
Smathev 2025-10-08 13:57:24 +02:00
parent f3afe70c10
commit ac0b03a50c
15 changed files with 1300 additions and 17 deletions

168
oled_font_helper.py Normal file
View 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()