From ac0b03a50ca654bda87d2052dc3839849cfbadea Mon Sep 17 00:00:00 2001 From: Smathev Date: Wed, 8 Oct 2025 13:57:24 +0200 Subject: [PATCH] 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. --- OLED_FIX_README.md | 139 ++++++++ backups/glcdfont.c.backup | 232 +++++++++++++ backups/keymap.c.backup | 321 ++++++++++++++++++ build_all.sh | 3 + generate_simple_icons.py | 184 ++++++++++ .../sweeeeep/keymaps/smathev/config.h | 4 + .../sweeeeep/keymaps/smathev/keymap.c | 35 +- .../sweeeeep/keymaps/smathev/rules.mk | 3 + oled_font_helper.py | 168 +++++++++ oled_redesign_128x32.c | 182 ++++++++++ users/smathev/config.h | 13 +- users/smathev/flow_tap.c | 20 ++ users/smathev/rules.mk | 3 + users/smathev/smathev.h | 3 +- users/smathev/wrappers.h | 7 + 15 files changed, 1300 insertions(+), 17 deletions(-) create mode 100644 OLED_FIX_README.md create mode 100644 backups/glcdfont.c.backup create mode 100644 backups/keymap.c.backup create mode 100644 generate_simple_icons.py create mode 100644 keyboards/fingerpunch/sweeeeep/keymaps/smathev/rules.mk create mode 100644 oled_font_helper.py create mode 100644 oled_redesign_128x32.c create mode 100644 users/smathev/flow_tap.c diff --git a/OLED_FIX_README.md b/OLED_FIX_README.md new file mode 100644 index 00000000..4859217f --- /dev/null +++ b/OLED_FIX_README.md @@ -0,0 +1,139 @@ +# OLED Display Fix for 128x32 Screens + +## Problem +Your OLED code was designed for larger displays (128x64) with 8 rows. Your 128x32 display only has **4 rows × 21 characters**, so the 3-row tall graphics take up most of the screen, leaving no room for useful information. + +## Solution Overview +1. **Simplify graphics**: Use 1-row tall icons (single character height) instead of 3-row tall graphics +2. **Optimize layout**: Better use of the 4 available rows +3. **Update font file**: Replace oversized graphics with compact, readable icons + +## New Layout for 128x32 (4 rows) +``` +Row 1: [Logo] LAYER NAME +Row 2: [Icon] W-C-S (modifiers) +Row 3: WPM:045 +Row 4: CAPS SCRL +``` + +## Files Modified + +### 1. OLED Code (keymap.c) +Replace your current OLED functions with the compact version in: +- `oled_redesign_128x32.c` (reference implementation) + +Key changes: +- **Logo**: 2 characters instead of 15 (3×5 grid) +- **Layer indicators**: 2 characters instead of 15 (3×5 grid) +- **Modifiers**: 4 single characters (W-A-C-S) instead of multi-char graphics +- **Text-based layer names**: More readable than icons +- **Efficient spacing**: Uses all 4 rows effectively + +### 2. Font File (glcdfont.c) +Update these character positions with simple icons: + +```c +// 0x80-0x81: Logo (2 chars) +0x3E, 0x41, 0x55, 0x55, 0x41, 0x3E, // 0x80: Keyboard icon +0x3E, 0x41, 0x55, 0x55, 0x41, 0x3E, // 0x81: Keyboard icon + +// 0x92-0x93: Default layer (2 chars) +0x08, 0x1C, 0x3E, 0x7F, 0x2A, 0x2A, // 0x92: Home icon +0x10, 0x38, 0x7C, 0xFE, 0x54, 0x54, // 0x93: Home icon + +// 0x94-0x95: Symbol layer (2 chars) +0x24, 0x7F, 0x24, 0x7F, 0x24, 0x00, // 0x94: # symbol +0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, // 0x95: $ symbol + +// 0x96-0x97: Navigation layer (2 chars) +0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, // 0x96: Up arrow +0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, // 0x97: Down arrow + +// 0x98-0x9B: Modifier keys (1 char each) +0x66, 0x66, 0x00, 0x7E, 0x66, 0x66, // 0x98: GUI/Windows +0x7E, 0x09, 0x09, 0x09, 0x7E, 0x00, // 0x99: ALT +0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, // 0x9A: CTRL +0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, // 0x9B: SHIFT (arrow) +``` + +## Implementation Steps + +### Step 1: Update keymap.c OLED functions +Copy the redesigned functions from `oled_redesign_128x32.c` to your `keymap.c`, replacing these functions: +- `render_logo()` → `render_logo_compact()` +- `render_logo2()` → (merged into main function) +- `render_layer_state()` → `render_layer_name()` + `render_layer_icon()` +- `render_mod_status_gui_alt()` → `render_modifiers_compact()` +- `render_mod_status_ctrl_shift()` → (merged into modifiers_compact) +- `render_status_main()` → `render_status_compact()` +- `render_status_secondary()` → (use same compact function) +- `oled_task_user()` → Updated version + +### Step 2: Update glcdfont.c +1. Find line ~136 where character 0x80 starts +2. Replace the hex values for characters 0x80, 0x81, 0x92-0x9B +3. Keep all other characters (0x00-0x7F for ASCII text) + +### Step 3: Compile and Test +```bash +cd qmk_userspace +bash build_all.sh +``` + +### Step 4: Flash to Keyboard +Flash the `.uf2` files to both halves of your split keyboard. + +## Customization + +### Design Your Own Icons +1. Visit: https://helixfonteditor.netlify.com/ +2. Each character is **6 pixels wide × 8 pixels tall** +3. Export as hex array (6 bytes per character) +4. Copy hex values to glcdfont.c + +### Character Format +Each character = 6 bytes (one per column): +``` +Byte format (binary): 0bDCBA9876 +where 0 = top pixel, 7 = bottom pixel + +Example (arrow up): + ▄ ▄▄▄ ▄ █ ▄ ▄ ▄ ▄ + █ ███ █ █ █ █ █ █ += [0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08] +``` + +### Alternative: Use Text Instead of Icons +If you prefer text-only (no custom graphics): +```c +// In render_modifiers_compact(): +if(modifiers & MOD_MASK_GUI) oled_write_P(PSTR("W"), false); +if(modifiers & MOD_MASK_ALT) oled_write_P(PSTR("A"), false); +if(modifiers & MOD_MASK_CTRL) oled_write_P(PSTR("C"), false); +if(modifiers & MOD_MASK_SHIFT) oled_write_P(PSTR("S"), false); +``` + +## Benefits of This Design + +✅ **Readable**: Text layer names are clearer than multi-row icons +✅ **Efficient**: Uses all 4 rows with no wasted space +✅ **Informative**: Shows layer, modifiers, WPM, and caps/scroll lock +✅ **Compact**: Small icons fit in single row (1 char tall) +✅ **Consistent**: Same layout on both keyboard halves +✅ **Maintainable**: Simpler code, easier to modify + +## Tools Provided + +1. **oled_font_helper.py**: Visualize current font graphics +2. **generate_simple_icons.py**: Generate simple icon hex values +3. **oled_redesign_128x32.c**: Complete redesigned OLED code + +## Next Steps + +Would you like me to: +1. Apply these changes directly to your keymap.c and glcdfont.c? +2. Create a different layout design? +3. Design custom icons for specific purposes? +4. Keep some of your original graphics but optimize them? + +Let me know how you'd like to proceed! diff --git a/backups/glcdfont.c.backup b/backups/glcdfont.c.backup new file mode 100644 index 00000000..6fbc1af8 --- /dev/null +++ b/backups/glcdfont.c.backup @@ -0,0 +1,232 @@ +#include "progmem.h" + +// Corne 8x6 font with QMK Firmware Logo +// Online editor: https://helixfonteditor.netlify.com/ +// See also: https://github.com/soundmonster/glcdfont_converter + +const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, + 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, + 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, + 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, + 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, + 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, + 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, + 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, + 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, + 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, + 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00, + 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, + 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, + 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, + 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, + 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, + 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, + 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, + 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, + 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, + 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, + 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, + 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, + 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, + 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, + 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, + 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, + 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, + 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, + 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, + 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, + 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, + 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, + 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, + 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, + 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, + 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, + 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, + 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, + 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, + 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, + 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, + 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, + 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, + 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, + 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, + 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, + 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, + 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, + 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, + 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, + 0x18, 0x24, 0x24, 0x1C, 0x78, 0x00, + 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x7C, 0x18, 0x24, 0x24, 0x18, 0x00, + 0x18, 0x24, 0x24, 0x18, 0x7C, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, + 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, + 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, + 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, + 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, + 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, + 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, + 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, + 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, + 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, + 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x78, + 0x7C, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7E, 0x7E, 0x7C, 0x78, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF8, 0x04, 0x22, 0x52, 0xE2, + 0x42, 0x42, 0x42, 0xE2, 0x52, 0x22, + 0x22, 0x22, 0x42, 0x82, 0x02, 0x02, + 0x22, 0x22, 0x02, 0x04, 0xF8, 0x00, + 0x00, 0xF8, 0x04, 0x02, 0x02, 0x82, + 0x42, 0x22, 0x42, 0x82, 0x02, 0x02, + 0x02, 0x82, 0x42, 0x22, 0x12, 0x22, + 0x42, 0x82, 0x02, 0x04, 0xF8, 0x00, + 0x00, 0xF8, 0xFC, 0xDE, 0xAE, 0x1E, + 0xBE, 0xBE, 0xBE, 0x1E, 0xAE, 0xDE, + 0xDE, 0xDE, 0xBE, 0x7E, 0xFE, 0xFE, + 0xDE, 0xDE, 0xFE, 0xFC, 0xF8, 0x00, + 0x00, 0xF8, 0xFC, 0xFE, 0xFE, 0x7E, + 0xBE, 0xDE, 0xBE, 0x7E, 0xFE, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, + 0x10, 0x10, 0x08, 0x08, 0x10, 0x10, + 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, + 0x80, 0x80, 0xC0, 0xC0, 0xE0, 0xE0, + 0xF0, 0xF0, 0xF8, 0xF8, 0xF0, 0xF0, + 0xE0, 0xE0, 0xC0, 0xC0, 0x80, 0x80, + 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, + 0x10, 0x10, 0x08, 0x08, 0x10, 0x10, + 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, + 0x80, 0x80, 0x40, 0xC0, 0x60, 0xA0, + 0x50, 0xB0, 0x58, 0xA8, 0x50, 0xB0, + 0x60, 0xA0, 0x40, 0xC0, 0x80, 0x80, + 0x00, 0x00, 0xC0, 0x67, 0xBF, 0x67, + 0xCC, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, + 0x7E, 0x7E, 0x3F, 0x7E, 0x7E, 0xFC, + 0xFC, 0xFC, 0xF8, 0xF8, 0xCC, 0x67, + 0xBF, 0x67, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0x20, 0x44, 0x4A, 0x47, + 0x42, 0x42, 0x42, 0x47, 0x4A, 0x44, + 0x40, 0x40, 0x40, 0x40, 0x41, 0x42, + 0x44, 0x44, 0x40, 0x20, 0x1F, 0x00, + 0x00, 0x1F, 0x20, 0x40, 0x41, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x41, 0x40, + 0x41, 0x41, 0x4F, 0x48, 0x48, 0x48, + 0x4F, 0x41, 0x41, 0x20, 0x1F, 0x00, + 0x00, 0x1F, 0x3F, 0x7B, 0x75, 0x78, + 0x7D, 0x7D, 0x7D, 0x78, 0x75, 0x7B, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7D, + 0x7B, 0x7B, 0x7F, 0x3F, 0x1F, 0x00, + 0x00, 0x1F, 0x3F, 0x7F, 0x7E, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x88, 0x5D, 0x5D, 0x3E, 0x3E, + 0x7C, 0x7C, 0xF8, 0xF8, 0x7C, 0x7C, + 0x3E, 0x3E, 0x5D, 0x5D, 0x88, 0x88, + 0x88, 0x88, 0x55, 0x55, 0x23, 0x23, + 0x47, 0x47, 0x8F, 0x8F, 0x47, 0x47, + 0x23, 0x23, 0x55, 0x55, 0x88, 0x88, + 0x88, 0x88, 0xD5, 0xD5, 0xE2, 0xE2, + 0xC4, 0xC4, 0x88, 0x88, 0xC4, 0xC4, + 0xE2, 0xE2, 0xD5, 0xD5, 0x88, 0x88, + 0x88, 0x88, 0x5D, 0xD5, 0x6B, 0xB6, + 0x6D, 0xD6, 0xAD, 0xDA, 0x6D, 0xD6, + 0x6B, 0xB6, 0x5D, 0xD5, 0x88, 0x88, + 0x00, 0x00, 0x03, 0x0F, 0x1E, 0x3D, + 0x7A, 0x9F, 0xAB, 0x89, 0x9D, 0x7C, + 0x5E, 0x8E, 0xF7, 0x8E, 0x5E, 0x7C, + 0x9D, 0x89, 0xAB, 0x9F, 0x7A, 0x3D, + 0x1E, 0x0F, 0x03, 0x00, 0x00, 0x00, + 0x04, 0xF8, 0x00, 0x00, 0xF8, 0x04, + 0x20, 0x1F, 0x00, 0x00, 0x1F, 0x20, + 0xFC, 0xF8, 0x00, 0x00, 0xF8, 0x04, + 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x20, + 0x04, 0xF8, 0x00, 0x00, 0xF8, 0xFC, + 0x20, 0x1F, 0x00, 0x00, 0x1F, 0x3F, + 0xFC, 0xF8, 0x00, 0x00, 0xF8, 0xFC, + 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, + 0xFE, 0x7E, 0xBE, 0xDE, 0xEE, 0xDE, + 0xBE, 0x7E, 0xFE, 0xFC, 0xF8, 0x00, + 0x7E, 0x7E, 0x70, 0x77, 0x77, 0x77, + 0x70, 0x7E, 0x7E, 0x3F, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, + 0x04, 0x04, 0x08, 0x08, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, + 0x04, 0x04, 0x08, 0x08, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, + 0x07, 0x07, 0x0F, 0x0F, 0x07, 0x07, + 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, + 0x05, 0x06, 0x0D, 0x0A, 0x05, 0x06, + 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, +}; diff --git a/backups/keymap.c.backup b/backups/keymap.c.backup new file mode 100644 index 00000000..9e245236 --- /dev/null +++ b/backups/keymap.c.backup @@ -0,0 +1,321 @@ +/* Copyright 2021 Sadek Baroudi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "smathev.h" +#include +#include "flow_tap.c" +#include "wrappers.h" +#include "casemodes.h" +#include QMK_KEYBOARD_H + +extern keymap_config_t keymap_config; +char wpm_str[6]; + +// clang-format off +#define LAYOUT_sweeeeep_base( \ + K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, \ + K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, \ + K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, \ + K33, K34, K35, K36, K37, K38 \ + ) \ + LAYOUT_wrapper( \ + K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, \ + K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, \ + K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, \ + LT(_NORTNAVIGATION, K33), K34, K35, K36, K37, LT(_SYMFKEYS, K38) \ + ) + +/* Re-pass though to allow templates to be used */ +#define LAYOUT_sweeeeep_base_wrapper(...) LAYOUT_sweeeeep_base(__VA_ARGS__) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + [_NORTO] = LAYOUT_sweeeeep_base_wrapper( + __________________NORTO_L1____________________, __________________NORTO_R1____________________, + __________________NORTO_L2____________________, __________________NORTO_R2____________________, + __________________NORTO_L3____________________, __________________NORTO_R3____________________, + __NORTO_THUMBS_6__ + ), + + [_NORTNAVIGATION] = LAYOUT_sweeeeep_base_wrapper( + ____________NORTNAVIGATION_1_______________, _________________NUMPAD_1__________________, + ____________NORTNAVIGATION_2_______________, _________________NUMPAD_2__________________, + ____________NORTNAVIGATION_3_______________, _________________NUMPAD_3__________________, + _______, _______, _______, _______, _______, TG(_SETUP) + ), + + [_SYMFKEYS] = LAYOUT_sweeeeep_base_wrapper( + ___________________FKEY______L1________________, ________________NORTSYMBOLS_R1_________________, + ___________________FKEY______L2________________, ________________NORTSYMBOLS_R2_________________, + ___________________FKEY______L3________________, ________________NORTSYMBOLS_R3_________________, + TG(_SETUP), _______, _______, _______, _______, _______ + ), + + [_SETUP] = LAYOUT_sweeeeep_base_wrapper( + __________________QWERTY_L1____________________, _________________KB_SETUP_1________________, + __________________QWERTY_L2____________________, _________________KB_SETUP_2________________, + __________________QWERTY_L3____________________, _________________KB_SETUP_3________________, + _______, TG(_SETUP), TG(_NORTO), TG(_NORTO), TG(_SETUP), _______ + ) + +}; + +const char chordal_hold_layout[MATRIX_ROWS][MATRIX_COLS] PROGMEM = + LAYOUT( + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + '*', 'L', 'L', 'R', 'R', '*' + ); +#ifdef OLED_ENABLE +// static uint32_t oled_timer = 0; + bool process_record_oled(uint16_t keycode, keyrecord_t *record); + oled_rotation_t oled_init_user(oled_rotation_t rotation); + void render_layer_symbol(void); + void render_layer_name(void); + void render_mod_state(uint8_t modifiers); + void render_status(void); + bool oled_task_user(void); +#endif +#ifdef OLED_ENABLE +oled_rotation_t oled_init_user(oled_rotation_t rotation) { return OLED_ROTATION_270; } + +void render_space(void) { + oled_write_P(PSTR(" "), false); +} + +void render_mod_status_gui_alt(uint8_t modifiers) { + static const char PROGMEM gui_off_1[] = {0x85, 0x86, 0}; + static const char PROGMEM gui_off_2[] = {0xa5, 0xa6, 0}; + static const char PROGMEM gui_on_1[] = {0x8d, 0x8e, 0}; + static const char PROGMEM gui_on_2[] = {0xad, 0xae, 0}; + + static const char PROGMEM alt_off_1[] = {0x87, 0x88, 0}; + static const char PROGMEM alt_off_2[] = {0xa7, 0xa8, 0}; + static const char PROGMEM alt_on_1[] = {0x8f, 0x90, 0}; + static const char PROGMEM alt_on_2[] = {0xaf, 0xb0, 0}; + + // fillers between the modifier icons bleed into the icon frames + static const char PROGMEM off_off_1[] = {0xc5, 0}; + static const char PROGMEM off_off_2[] = {0xc6, 0}; + static const char PROGMEM on_off_1[] = {0xc7, 0}; + static const char PROGMEM on_off_2[] = {0xc8, 0}; + static const char PROGMEM off_on_1[] = {0xc9, 0}; + static const char PROGMEM off_on_2[] = {0xca, 0}; + static const char PROGMEM on_on_1[] = {0xcb, 0}; + static const char PROGMEM on_on_2[] = {0xcc, 0}; + + if(modifiers & MOD_MASK_GUI) { + oled_write_P(gui_on_1, false); + } else { + oled_write_P(gui_off_1, false); + } + + if ((modifiers & MOD_MASK_GUI) && (modifiers & MOD_MASK_ALT)) { + oled_write_P(on_on_1, false); + } else if(modifiers & MOD_MASK_GUI) { + oled_write_P(on_off_1, false); + } else if(modifiers & MOD_MASK_ALT) { + oled_write_P(off_on_1, false); + } else { + oled_write_P(off_off_1, false); + } + + if(modifiers & MOD_MASK_ALT) { + oled_write_P(alt_on_1, false); + } else { + oled_write_P(alt_off_1, false); + } + + if(modifiers & MOD_MASK_GUI) { + oled_write_P(gui_on_2, false); + } else { + oled_write_P(gui_off_2, false); + } + + if ((modifiers & MOD_MASK_GUI) && (modifiers & MOD_MASK_ALT)) { + oled_write_P(on_on_2, false); + } else if(modifiers & MOD_MASK_GUI) { + oled_write_P(on_off_2, false); + } else if(modifiers & MOD_MASK_ALT) { + oled_write_P(off_on_2, false); + } else { + oled_write_P(off_off_2, false); + } + + if(modifiers & MOD_MASK_ALT) { + oled_write_P(alt_on_2, false); + } else { + oled_write_P(alt_off_2, false); + } +} + + +void render_mod_status_ctrl_shift(uint8_t modifiers) { + static const char PROGMEM ctrl_off_1[] = {0x89, 0x8a, 0}; + static const char PROGMEM ctrl_off_2[] = {0xa9, 0xaa, 0}; + static const char PROGMEM ctrl_on_1[] = {0x91, 0x92, 0}; + static const char PROGMEM ctrl_on_2[] = {0xb1, 0xb2, 0}; + + static const char PROGMEM shift_off_1[] = {0x8b, 0x8c, 0}; + static const char PROGMEM shift_off_2[] = {0xab, 0xac, 0}; + static const char PROGMEM shift_on_1[] = {0xcd, 0xce, 0}; + static const char PROGMEM shift_on_2[] = {0xcf, 0xd0, 0}; + + // fillers between the modifier icons bleed into the icon frames + static const char PROGMEM off_off_1[] = {0xc5, 0}; + static const char PROGMEM off_off_2[] = {0xc6, 0}; + static const char PROGMEM on_off_1[] = {0xc7, 0}; + static const char PROGMEM on_off_2[] = {0xc8, 0}; + static const char PROGMEM off_on_1[] = {0xc9, 0}; + static const char PROGMEM off_on_2[] = {0xca, 0}; + static const char PROGMEM on_on_1[] = {0xcb, 0}; + static const char PROGMEM on_on_2[] = {0xcc, 0}; + + if(modifiers & MOD_MASK_CTRL) { + oled_write_P(ctrl_on_1, false); + } else { + oled_write_P(ctrl_off_1, false); + } + + if ((modifiers & MOD_MASK_CTRL) && (modifiers & MOD_MASK_SHIFT)) { + oled_write_P(on_on_1, false); + } else if(modifiers & MOD_MASK_CTRL) { + oled_write_P(on_off_1, false); + } else if(modifiers & MOD_MASK_SHIFT) { + oled_write_P(off_on_1, false); + } else { + oled_write_P(off_off_1, false); + } + + if(modifiers & MOD_MASK_SHIFT) { + oled_write_P(shift_on_1, false); + } else { + oled_write_P(shift_off_1, false); + } + + if(modifiers & MOD_MASK_CTRL) { + oled_write_P(ctrl_on_2, false); + } else { + oled_write_P(ctrl_off_2, false); + } + + if ((modifiers & MOD_MASK_CTRL) && (modifiers & MOD_MASK_SHIFT)) { + oled_write_P(on_on_2, false); + } else if(modifiers & MOD_MASK_CTRL) { + oled_write_P(on_off_2, false); + } else if(modifiers & MOD_MASK_SHIFT) { + oled_write_P(off_on_2, false); + } else { + oled_write_P(off_off_2, false); + } + + if(modifiers & MOD_MASK_SHIFT) { + oled_write_P(shift_on_2, false); + } else { + oled_write_P(shift_off_2, false); + } +} + +void render_logo(void) { + static const char PROGMEM corne_logo[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0}; + oled_write_P(corne_logo, false); + oled_write_P(PSTR("Gio*K"), false); +} + +void render_logo2(void) { + static const char PROGMEM corne_logo[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0}; + oled_write_P(corne_logo, false); + sprintf(wpm_str,">>%03d", get_current_wpm()); + oled_write(wpm_str,false); +} + + +void render_layer_state(void) { + static const char PROGMEM default_layer[] = { + 0x20, 0x94, 0x95, 0x96, 0x20, + 0x20, 0xb4, 0xb5, 0xb6, 0x20, + 0x20, 0xd4, 0xd5, 0xd6, 0x20, 0}; + static const char PROGMEM raise_layer[] = { + 0x20, 0x97, 0x98, 0x99, 0x20, + 0x20, 0xb7, 0xb8, 0xb9, 0x20, + 0x20, 0xd7, 0xd8, 0xd9, 0x20, 0}; + static const char PROGMEM lower_layer[] = { + 0x20, 0x9a, 0x9b, 0x9c, 0x20, + 0x20, 0xba, 0xbb, 0xbc, 0x20, + 0x20, 0xda, 0xdb, 0xdc, 0x20, 0}; + if(layer_state_is(_SYMFKEYS)) { + oled_write_P(lower_layer, false); + } else if(layer_state_is(_NORTNAVIGATION)) { + oled_write_P(raise_layer, false); + } else { + oled_write_P(default_layer, false); + } +} + +void render_status_main(void) { + render_logo(); + render_space(); + render_layer_state(); + render_space(); + render_mod_status_gui_alt(get_mods()|get_oneshot_mods()); + render_mod_status_ctrl_shift(get_mods()|get_oneshot_mods()); +} + +void render_status_secondary(void) { + render_logo2(); + render_space(); + render_layer_state(); + render_space(); + render_mod_status_gui_alt(get_mods()|get_oneshot_mods()); + render_mod_status_ctrl_shift(get_mods()|get_oneshot_mods()); +} + + static bool oled_active = true; + + bool process_record_user_keymap(uint16_t keycode, keyrecord_t *record) { + return true; + } + + bool oled_task_user(void) { + if (last_input_activity_elapsed() > 15000) { + if (oled_active) { // Only turn off if it's currently on + oled_off(); + oled_active = false; + } + return false; // Don't render while sleeping + } + + // If we get here, there's been recent activity + if (!oled_active) { + oled_on(); + oled_active = true; + } + + if (is_keyboard_master()) { + render_status_main(); + } else { + render_status_secondary(); + } + return false; + } + +#endif + diff --git a/build_all.sh b/build_all.sh index 14d58440..2cdf8221 100755 --- a/build_all.sh +++ b/build_all.sh @@ -29,6 +29,9 @@ echo "" # Clean build echo "🧹 Cleaning previous build..." qmk clean > /dev/null 2>&1 +echo "🧹 Cleaning previous output files..." +rm -rf "$OUTPUT_DIR/${OUTPUT_NAME}.uf2" "$OUTPUT_DIR/${OUTPUT_NAME}_LEFT.uf2" "$OUTPUT_DIR/${OUTPUT_NAME}_RIGHT.uf2" +mkdir -p "$OUTPUT_DIR" echo "" # ============================================================================ diff --git a/generate_simple_icons.py b/generate_simple_icons.py new file mode 100644 index 00000000..34e7fe0f --- /dev/null +++ b/generate_simple_icons.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +""" +Generate a minimal custom font section for 128x32 OLED displays +This creates simple, readable icons that fit in a single row +""" + +def generate_simple_icons(): + """Generate simple icon designs for the custom characters""" + + icons = {} + + # 0x80-0x81: Logo (simple keyboard icon) + # Row 1 of 2-char logo + icons[0x80] = [ + 0b00111110, # | ████ + 0b01000001, # | █ █ + 0b01010101, # | █ █ █ + 0b01010101, # | █ █ █ + 0b01000001, # | █ █ + 0b00111110, # | ████ + ] + # Row 2 of 2-char logo + icons[0x81] = [ + 0b00111110, # | ████ + 0b01000001, # | █ █ + 0b01010101, # | █ █ █ + 0b01010101, # | █ █ █ + 0b01000001, # | █ █ + 0b00111110, # | ████ + ] + + # 0x92-0x93: Default/Base layer icon (house or keyboard) + icons[0x92] = [ + 0b00001000, # | █ + 0b00011100, # | ███ + 0b00111110, # | █████ + 0b01111111, # | ███████ + 0b00101010, # | █ █ █ + 0b00101010, # | █ █ █ + ] + icons[0x93] = [ + 0b00010000, # | █ + 0b00111000, # | ███ + 0b01111100, # | █████ + 0b11111110, # | ███████ + 0b01010100, # | █ █ █ + 0b01010100, # | █ █ █ + ] + + # 0x94-0x95: Symbol layer icon (# and $) + icons[0x94] = [ + 0b00100100, # | █ █ + 0b01111111, # | ███████ + 0b00100100, # | █ █ + 0b01111111, # | ███████ + 0b00100100, # | █ █ + 0b00000000, # | + ] + icons[0x95] = [ + 0b00100100, # | █ █ + 0b00101010, # | █ █ █ + 0b01111111, # | ███████ + 0b00101010, # | █ █ █ + 0b00010010, # | █ █ + 0b00000000, # | + ] + + # 0x96-0x97: Navigation layer icon (arrows) + icons[0x96] = [ + 0b00001000, # | █ + 0b00011100, # | ███ + 0b00101010, # | █ █ █ + 0b00001000, # | █ + 0b00001000, # | █ + 0b00001000, # | █ + ] + icons[0x97] = [ + 0b00001000, # | █ + 0b00001000, # | █ + 0b00001000, # | █ + 0b00101010, # | █ █ █ + 0b00011100, # | ███ + 0b00001000, # | █ + ] + + # 0x98: GUI/Windows key (simple windows logo) + icons[0x98] = [ + 0b01100110, # | ██ ██ + 0b01100110, # | ██ ██ + 0b00000000, # | + 0b01111110, # | ██████ + 0b01100110, # | ██ ██ + 0b01100110, # | ██ ██ + ] + + # 0x99: ALT key (simple A) + icons[0x99] = [ + 0b01111110, # | ██████ + 0b00001001, # | █ █ + 0b00001001, # | █ █ + 0b00001001, # | █ █ + 0b01111110, # | ██████ + 0b00000000, # | + ] + + # 0x9A: CTRL key (simple C) + icons[0x9A] = [ + 0b00111110, # | █████ + 0b01000001, # | █ █ + 0b01000001, # | █ █ + 0b01000001, # | █ █ + 0b00100010, # | █ █ + 0b00000000, # | + ] + + # 0x9B: SHIFT key (up arrow) + icons[0x9B] = [ + 0b00001000, # | █ + 0b00011100, # | ███ + 0b00101010, # | █ █ █ + 0b00001000, # | █ + 0b00001000, # | █ + 0b00001000, # | █ + ] + + return icons + +def format_hex_array(byte_array): + """Format a byte array as hex values for C code""" + return ", ".join(f"0x{b:02X}" for b in byte_array) + +def main(): + print("="*70) + print("SIMPLE ICON GENERATOR FOR 128x32 OLED") + print("="*70) + print("\nThis generates simple, single-row icons for your custom font.") + print("Copy these hex values into your glcdfont.c file.\n") + + icons = generate_simple_icons() + + print("// ====================================================================") + print("// CUSTOM ICONS FOR 128x32 DISPLAY") + print("// Add these to your glcdfont.c at the appropriate positions") + print("// ====================================================================\n") + + descriptions = { + 0x80: "Logo part 1 (keyboard icon)", + 0x81: "Logo part 2 (keyboard icon)", + 0x92: "Default layer icon part 1 (home/keyboard)", + 0x93: "Default layer icon part 2 (home/keyboard)", + 0x94: "Symbol layer icon part 1 (# symbol)", + 0x95: "Symbol layer icon part 2 ($ symbol)", + 0x96: "Navigation layer icon part 1 (up arrow)", + 0x97: "Navigation layer icon part 2 (down arrow)", + 0x98: "GUI/Windows modifier key", + 0x99: "ALT modifier key", + 0x9A: "CTRL modifier key", + 0x9B: "SHIFT modifier key (up arrow)", + } + + for code in sorted(icons.keys()): + print(f" // Character 0x{code:02X} ({code}): {descriptions.get(code, '')}") + print(f" {format_hex_array(icons[code])},") + print() + + print("\n" + "="*70) + print("USAGE INSTRUCTIONS:") + print("="*70) + print(""" +1. Open your glcdfont.c file +2. Find the position where character 0x80 starts (around line 136) +3. Replace the hex values at positions 0x80, 0x81, 0x92-0x9B with the above +4. Save and recompile your firmware +5. Use the redesigned OLED code from oled_redesign_128x32.c + +TIP: To customize these icons further, use: + https://helixfonteditor.netlify.com/ + +Each character is 6 bytes representing 6 columns of 8 pixels. +Bit 0 = top pixel, Bit 7 = bottom pixel in each column. +""") + +if __name__ == "__main__": + main() diff --git a/keyboards/fingerpunch/sweeeeep/keymaps/smathev/config.h b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/config.h index 47d2f9e3..293c3c0c 100644 --- a/keyboards/fingerpunch/sweeeeep/keymaps/smathev/config.h +++ b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/config.h @@ -25,6 +25,10 @@ // IMPORTANT: This must be set for EE_HANDS to work properly #define EE_HANDS +#ifdef OLED_ENABLE +#define OLED_DISPLAY_128X32 +#endif + // Alternative methods (comment out EE_HANDS and use one of these if needed): // #define MASTER_LEFT // Left half is always master (USB connection side) // #define MASTER_RIGHT // Right half is always master (USB connection side) diff --git a/keyboards/fingerpunch/sweeeeep/keymaps/smathev/keymap.c b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/keymap.c index 447706c1..d1c4616f 100644 --- a/keyboards/fingerpunch/sweeeeep/keymaps/smathev/keymap.c +++ b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/keymap.c @@ -15,6 +15,7 @@ */ #include "smathev.h" #include +//#include "flow_tap.c" #include "wrappers.h" #include "casemodes.h" #include QMK_KEYBOARD_H @@ -47,29 +48,39 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { __NORTO_THUMBS_6__ ), - [_QWERTY] = LAYOUT_sweeeeep_base_wrapper( - __________________QWERTY_L1____________________, __________________QWERTY_R1____________________, - __________________QWERTY_L2____________________, __________________QWERTY_R2____________________, - __________________QWERTY_L3____________________, __________________QWERTY_R3____________________, - __QWERTY_THUMBS_6__ - ), - [_NORTNAVIGATION] = LAYOUT_sweeeeep_base_wrapper( ____________NORTNAVIGATION_1_______________, _________________NUMPAD_1__________________, ____________NORTNAVIGATION_2_______________, _________________NUMPAD_2__________________, ____________NORTNAVIGATION_3_______________, _________________NUMPAD_3__________________, - _______, TG(_NORTO), TG(_QWERTY), TG(_QWERTY), TG(_NORTO), _______ + _______, _______, _______, _______, _______, TG(_SETUP) ), [_SYMFKEYS] = LAYOUT_sweeeeep_base_wrapper( ___________________FKEY______L1________________, ________________NORTSYMBOLS_R1_________________, ___________________FKEY______L2________________, ________________NORTSYMBOLS_R2_________________, ___________________FKEY______L3________________, ________________NORTSYMBOLS_R3_________________, - _______, TG(_NORTO), TG(_QWERTY), TG(_QWERTY), TG(_NORTO), _______ + TG(_SETUP), _______, _______, _______, _______, _______ + ), + + [_SETUP] = LAYOUT_sweeeeep_base_wrapper( + __________________QWERTY_L1____________________, _________________KB_SETUP_1________________, + __________________QWERTY_L2____________________, _________________KB_SETUP_2________________, + __________________QWERTY_L3____________________, _________________KB_SETUP_3________________, + _______, TG(_SETUP), TG(_NORTO), TG(_NORTO), TG(_SETUP), _______ ) + }; - +// Chordal hold layout (disabled - conflicts with multi-modifier shortcuts) +/* +const char chordal_hold_layout[MATRIX_ROWS][MATRIX_COLS] PROGMEM = + LAYOUT( + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + 'L', 'L', 'L', 'L', 'L', 'R', 'R', 'R', 'R', 'R', + '*', 'L', 'L', 'R', 'R', '*' + ); +*/ #ifdef OLED_ENABLE // static uint32_t oled_timer = 0; bool process_record_oled(uint16_t keycode, keyrecord_t *record); @@ -253,9 +264,9 @@ void render_layer_state(void) { 0x20, 0x9a, 0x9b, 0x9c, 0x20, 0x20, 0xba, 0xbb, 0xbc, 0x20, 0x20, 0xda, 0xdb, 0xdc, 0x20, 0}; - if(layer_state_is(_SYMBOLS)) { + if(layer_state_is(_SYMFKEYS)) { oled_write_P(lower_layer, false); - } else if(layer_state_is(_NAVIGATION)) { + } else if(layer_state_is(_NORTNAVIGATION)) { oled_write_P(raise_layer, false); } else { oled_write_P(default_layer, false); diff --git a/keyboards/fingerpunch/sweeeeep/keymaps/smathev/rules.mk b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/rules.mk new file mode 100644 index 00000000..811b17a6 --- /dev/null +++ b/keyboards/fingerpunch/sweeeeep/keymaps/smathev/rules.mk @@ -0,0 +1,3 @@ +# Keymap-specific features +OLED_ENABLE = yes +OLED_DRIVER = ssd1306 # Standard I2C OLED driver diff --git a/oled_font_helper.py b/oled_font_helper.py new file mode 100644 index 00000000..df90d5f9 --- /dev/null +++ b/oled_font_helper.py @@ -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() diff --git a/oled_redesign_128x32.c b/oled_redesign_128x32.c new file mode 100644 index 00000000..c6bbdc29 --- /dev/null +++ b/oled_redesign_128x32.c @@ -0,0 +1,182 @@ +// ============================================================================ +// IMPROVED OLED CODE FOR 128x32 DISPLAYS (4 rows × 21 characters) +// ============================================================================ +// This is a redesigned OLED layout that fits properly on 128x32 displays +// +// Layout strategy for 4 rows: +// Row 1: Small logo/icon (2-3 chars) + Layer name (text) +// Row 2: Layer icon (2-3 chars) + Modifier status indicators +// Row 3: WPM counter or other stats +// Row 4: Additional info (caps lock, scroll lock, etc.) +// +// To use this code, replace the OLED functions in your keymap.c +// ============================================================================ + +#ifdef OLED_ENABLE + +void render_space(void) { + oled_write_P(PSTR(" "), false); +} + +void render_newline(void) { + oled_write_P(PSTR("\n"), false); +} + +// Compact logo - just 2 characters wide for 128x32 +void render_logo_compact(void) { + // Use a simple 2-char logo (you can design these at positions 0x80-0x81) + static const char PROGMEM logo[] = {0x80, 0x81, 0}; + oled_write_P(logo, false); +} + +// Text-based layer display (more readable on small screens) +void render_layer_name(void) { + if(layer_state_is(_SYMFKEYS)) { + oled_write_P(PSTR(" SYMBOLS"), false); + } else if(layer_state_is(_NORTNAVIGATION)) { + oled_write_P(PSTR(" NAVIGATE"), false); + } else if(layer_state_is(_QWERTY)) { + oled_write_P(PSTR(" QWERTY"), false); + } else { + oled_write_P(PSTR(" NORTO"), false); + } +} + +// Compact 2-char layer icon +void render_layer_icon(void) { + if(layer_state_is(_SYMFKEYS)) { + // Symbol layer icon (2 chars: 0x94-0x95) + static const char PROGMEM symbol_icon[] = {0x94, 0x95, 0}; + oled_write_P(symbol_icon, false); + } else if(layer_state_is(_NORTNAVIGATION)) { + // Navigation layer icon (2 chars: 0x96-0x97) + static const char PROGMEM nav_icon[] = {0x96, 0x97, 0}; + oled_write_P(nav_icon, false); + } else { + // Default layer icon (2 chars: 0x92-0x93) + static const char PROGMEM default_icon[] = {0x92, 0x93, 0}; + oled_write_P(default_icon, false); + } +} + +// Compact modifier status - single character per modifier +void render_modifiers_compact(uint8_t modifiers) { + // GUI/Super (1 char) + if(modifiers & MOD_MASK_GUI) { + oled_write_P(PSTR("W"), false); // Or use custom char 0x98 + } else { + oled_write_P(PSTR("-"), false); + } + + // ALT (1 char) + if(modifiers & MOD_MASK_ALT) { + oled_write_P(PSTR("A"), false); // Or use custom char 0x99 + } else { + oled_write_P(PSTR("-"), false); + } + + // CTRL (1 char) + if(modifiers & MOD_MASK_CTRL) { + oled_write_P(PSTR("C"), false); // Or use custom char 0x9A + } else { + oled_write_P(PSTR("-"), false); + } + + // SHIFT (1 char) + if(modifiers & MOD_MASK_SHIFT) { + oled_write_P(PSTR("S"), false); // Or use custom char 0x9B + } else { + oled_write_P(PSTR("-"), false); + } +} + +void render_wpm(void) { + char wpm_str[16]; + sprintf(wpm_str, "WPM:%03d", get_current_wpm()); + oled_write(wpm_str, false); +} + +void render_status_compact(void) { + // Row 1: Logo + Layer name + render_logo_compact(); + render_layer_name(); + render_newline(); + + // Row 2: Layer icon + Modifiers + render_layer_icon(); + render_space(); + render_modifiers_compact(get_mods()|get_oneshot_mods()); + render_newline(); + + // Row 3: WPM + render_wpm(); + render_newline(); + + // Row 4: Additional status + led_t led_state = host_keyboard_led_state(); + oled_write_P(led_state.caps_lock ? PSTR("CAPS ") : PSTR(" "), false); + oled_write_P(led_state.scroll_lock ? PSTR("SCRL ") : PSTR(" "), false); +} + +static bool oled_active = true; + +bool process_record_user_keymap(uint16_t keycode, keyrecord_t *record) { + return true; +} + +bool oled_task_user(void) { + // Auto-sleep after 15 seconds of inactivity + if (last_input_activity_elapsed() > 15000) { + if (oled_active) { + oled_off(); + oled_active = false; + } + return false; + } + + if (!oled_active) { + oled_on(); + oled_active = true; + } + + // Same display on both halves for 128x32 + render_status_compact(); + + return false; +} + +#endif + +// ============================================================================ +// FONT DESIGN GUIDE for 128x32 displays +// ============================================================================ +// +// Character positions you need to design: +// +// 0x80-0x81: Small logo (2 chars wide, 1 row tall) +// Design a simple keyboard icon or your initials +// +// 0x92-0x93: Default layer icon (2 chars, 1 row) +// Suggestion: Simple keyboard outline +// +// 0x94-0x95: Symbol layer icon (2 chars, 1 row) +// Suggestion: # $ % & symbols +// +// 0x96-0x97: Navigation layer icon (2 chars, 1 row) +// Suggestion: Arrow keys design +// +// 0x98: GUI/Super modifier icon (1 char) +// Suggestion: Windows logo or Super key +// +// 0x99: ALT modifier icon (1 char) +// Suggestion: "ALT" text or alt symbol +// +// 0x9A: CTRL modifier icon (1 char) +// Suggestion: "CTL" text or ctrl symbol +// +// 0x9B: SHIFT modifier icon (1 char) +// Suggestion: Up arrow or shift symbol +// +// Use https://helixfonteditor.netlify.com/ to design these characters. +// Each character is 6 pixels wide × 8 pixels tall. +// Keep designs simple and readable at small size! diff --git a/users/smathev/config.h b/users/smathev/config.h index 251368ae..b77ac055 100644 --- a/users/smathev/config.h +++ b/users/smathev/config.h @@ -23,16 +23,21 @@ // ============================================================================ // Tapping and timing configuration -#define TAPPING_TERM 140 -#define PERMISSIVE_HOLD // Activate mod immediately when another key pressed -#define AUTO_SHIFT_TIMEOUT 170 // Slightly longer than TAPPING_TERM +#define TAPPING_TERM 200 +//#define FLOW_TAP +//#define PERMISSIVE_HOLD // Activate mod immediately when another key pressed _REDUNDANT due to SpeculativeHold +#define AUTO_SHIFT_TIMEOUT 150 // Slightly longer than TAPPING_TERM #define RETRO_SHIFT // Enable retroactive shift #define RETRO_TAPPING // Enable retroactive tapping #define HOLD_ON_OTHER_KEY_PRESS // Enable hold on other key press -#define CHORDAL_HOLD // Enable chordal hold (mod activates if another key is pressed before tapping term) +//#define CHORDAL_HOLD // Enable chordal hold (mod activates if another key is pressed before tapping term) + // DISABLED: Conflicts with multi-modifier shortcuts like Ctrl+Shift+P // Combo configuration #define CASEMODES_ENABLE #define COMBO_REF_DEFAULT _NORTO +#ifdef OLED_ENABLE +#define OLED_DISPLAY_128X32 +#endif diff --git a/users/smathev/flow_tap.c b/users/smathev/flow_tap.c new file mode 100644 index 00000000..e5631135 --- /dev/null +++ b/users/smathev/flow_tap.c @@ -0,0 +1,20 @@ +#include "keymap_danish.h" + +bool is_flow_tap_key(uint16_t keycode) { + if ((get_mods() & (MOD_MASK_CG | MOD_BIT_LALT)) != 0) { + return false; // Disable Flow Tap on hotkeys. + } + switch (get_tap_keycode(keycode)) { + case KC_SPC: + case KC_A ... KC_Z: + case KC_DOT: + case KC_COMM: + case DK_SCLN: + case DK_SLSH: + case DK_ARNG: + case DK_OSTR: + case DK_AE: + return true; + } + return false; +} diff --git a/users/smathev/rules.mk b/users/smathev/rules.mk index 85a42f9c..212ec453 100644 --- a/users/smathev/rules.mk +++ b/users/smathev/rules.mk @@ -15,6 +15,8 @@ COMBO_ENABLE = yes # Combo key feature INTROSPECTION_KEYMAP_C = keyboards/fingerpunch/sweeeeep/keymaps/smathev/keymap.c AUTO_SHIFT_ENABLE = yes # Auto shift for hold-to-shift +OLED_ENABLE = yes # Enable OLED displays +OLED_DRIVER = ssd1306 # Standard I2C OLED driver (SSD1306) # Implemented from https://github.com/samhocevar-forks/qmk-firmware/blob/master/docs/feature_tap_dance.md # TAP_DANCE_ENABLE = yes @@ -28,3 +30,4 @@ CASEMODE_ENABLE = yes #WPM ENABLE WPM_ENABLE = yes +DYNAMIC_TAPPING_TERM_ENABLE = yes diff --git a/users/smathev/smathev.h b/users/smathev/smathev.h index 7b18280f..2fc69052 100644 --- a/users/smathev/smathev.h +++ b/users/smathev/smathev.h @@ -28,7 +28,8 @@ enum userspace_layers { _NORTO= 0, _QWERTY, _NORTNAVIGATION, - _SYMFKEYS + _SYMFKEYS, + _SETUP }; void press_super_alt_tab(bool shift); diff --git a/users/smathev/wrappers.h b/users/smathev/wrappers.h index 11174228..77e1ce65 100644 --- a/users/smathev/wrappers.h +++ b/users/smathev/wrappers.h @@ -279,6 +279,13 @@ NOTE: These are all the same length. If you do a search/replace // GAMES_LAYER? + +#define _________________KB_SETUP_1________________ AS_UP, DT_UP, KC_C, KC_V, KC_G +#define _________________KB_SETUP_2________________ AS_DOWN, DT_DOWN, KC_E, KC_R, KC_D +#define _________________KB_SETUP_3________________ AS_RPT, DT_PRNT, KC_TAB, KC_L, KC_H +#define _________________KB_SETUP_4________________ KC_T, KC_COMM, KC_K, KC_SCLN, KC_DOT + + #define ___________________GAMES_0_________________ KC_F1, KC_F2, KC_C, KC_V, KC_G #define ___________________GAMES_1_________________ KC_Q, KC_W, KC_E, KC_R, KC_D #define ___________________GAMES_2_________________ KC_A, KC_F, KC_TAB, KC_L, KC_H