summaryrefslogtreecommitdiff
path: root/keyboards/snes_macropad/snes_macropad.c
blob: ba4ce44bd1e04785018018497bf72770c4cbee50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2023 John Barbero Unenge (@jbarberu)
// SPDX-License-Identifier: GPL-2.0-or-later

#include "quantum.h"

// oled keylog rendering has been kindly borrowed from crkbd <3

char     key_name = ' ';
uint16_t last_keycode;
uint8_t  last_row;
uint8_t  last_col;

static const char PROGMEM code_to_name[60] = {' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'R', 'E', 'B', 'T', '_', '-', '=', '[', ']', '\\', '#', ';', '\'', '`', ',', '.', '/', ' ', ' ', ' '};

static void set_keylog(uint16_t keycode, keyrecord_t *record) {
    last_row = record->event.key.row;
    last_col = record->event.key.col;

    key_name     = ' ';
    last_keycode = keycode;
    if (IS_QK_MOD_TAP(keycode)) {
        if (record->tap.count) {
          keycode = QK_MOD_TAP_GET_TAP_KEYCODE(keycode);
        } else {
          keycode = 0xE0 + biton(QK_MOD_TAP_GET_MODS(keycode) & 0xF) + biton(QK_MOD_TAP_GET_MODS(keycode) & 0x10);
        }
    } else if (IS_QK_LAYER_TAP(keycode) && record->tap.count) {
        keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(keycode);
    } else if (IS_QK_MODS(keycode)) {
        keycode = QK_MODS_GET_BASIC_KEYCODE(keycode);
    } else if (IS_QK_ONE_SHOT_MOD(keycode)) {
        keycode = 0xE0 + biton(QK_ONE_SHOT_MOD_GET_MODS(keycode) & 0xF) + biton(QK_ONE_SHOT_MOD_GET_MODS(keycode) & 0x10);
    }
    if (keycode > ARRAY_SIZE(code_to_name)) {
        return;
    }

    // update keylog
    key_name = pgm_read_byte(&code_to_name[keycode]);
}

static const char *depad_str(const char *depad_str, char depad_char) {
    while (*depad_str == depad_char) {
        ++depad_str;
    }
    return depad_str;
}

static void oled_render_keylog(void) {
    oled_write_char('0' + last_row, false);
    oled_write("x", false);
    oled_write_char('0' + last_col, false);
    oled_write(", k", false);
    const char *last_keycode_str = get_u16_str(last_keycode, ' ');
    oled_write(depad_str(last_keycode_str, ' '), false);
    oled_write(":", false);
    oled_write_char(key_name, false);
}

__attribute__((weak)) const char * get_layer_name_user(uint8_t layer) {
    return get_u8_str(layer, ' ');
}

static void oled_render_layer(void) {
    oled_write("Layer: ", false);
    oled_write_ln(get_layer_name_user(get_highest_layer(layer_state)), false);
}

bool oled_task_kb(void) {
    if (!oled_task_user()) {
        return false;
    }

    oled_render_layer();
    oled_render_keylog();
    oled_advance_page(true);
    return false;
}

static void setupForFlashing(void) {
    oled_clear();
    oled_write("                     ", false);
    oled_write("  In flash mode...   ", false);
    oled_write("                     ", false);
    oled_write("                     ", false);

    // QMK is clever about only rendering a certain number of chunks per frame,
    // but since the device will go into flash mode right after this call,
    // we want to override this behavior and force all the chunks to be sent to
    // the display immediately.
    const size_t numIterations = OLED_DISPLAY_WIDTH * OLED_DISPLAY_HEIGHT / OLED_UPDATE_PROCESS_LIMIT;
    for (size_t num = 0; num < numIterations; ++num) {
        oled_render();
    }
    // todo: Replace the above hack with this, once develop branch is merged at the end of November 2023
    // oled_render_dirty(true);

    // Set alternating backlight colors
    const uint8_t max = 20;
    rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
    for (size_t i = 0; i < RGBLED_NUM; ++i) {
        LED_TYPE *led_ = (LED_TYPE *)&led[i];
        switch (i % 2) {
            case 0:
                setrgb(max, 0, max, led_);
                break;
            case 1:
                setrgb(0, max, max, led_);
                break;
        }
    }
    rgblight_set();
}

bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
    if (record->event.pressed) {
        set_keylog(keycode, record);
    }
    if (keycode == QK_BOOT) {
        setupForFlashing();
    }
    return process_record_user(keycode, record);
}

void keyboard_post_init_kb(void) {
    rgblight_enable_noeeprom();
    rgblight_sethsv_noeeprom(HSV_MAGENTA);
    rgblight_mode_noeeprom(RGBLIGHT_MODE_RAINBOW_SWIRL);
    keyboard_post_init_user();
}