qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

dynamic_keymap.c (5779B)


      1 /* Copyright 2017 Jason Williams (Wilba)
      2  * Copyright 2024-2025 Nick Brassel (@tzarc)
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #include "dynamic_keymap.h"
     19 #include "keymap_introspection.h"
     20 #include "action.h"
     21 #include "send_string.h"
     22 #include "keycodes.h"
     23 #include "nvm_dynamic_keymap.h"
     24 
     25 #ifdef ENCODER_ENABLE
     26 #    include "encoder.h"
     27 #else
     28 #    define NUM_ENCODERS 0
     29 #endif
     30 
     31 #ifndef DYNAMIC_KEYMAP_MACRO_DELAY
     32 #    define DYNAMIC_KEYMAP_MACRO_DELAY TAP_CODE_DELAY
     33 #endif
     34 
     35 uint8_t dynamic_keymap_get_layer_count(void) {
     36     return DYNAMIC_KEYMAP_LAYER_COUNT;
     37 }
     38 
     39 uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) {
     40     return nvm_dynamic_keymap_read_keycode(layer, row, column);
     41 }
     42 
     43 void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) {
     44     nvm_dynamic_keymap_update_keycode(layer, row, column, keycode);
     45 }
     46 
     47 #ifdef ENCODER_MAP_ENABLE
     48 uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise) {
     49     return nvm_dynamic_keymap_read_encoder(layer, encoder_id, clockwise);
     50 }
     51 
     52 void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) {
     53     nvm_dynamic_keymap_update_encoder(layer, encoder_id, clockwise, keycode);
     54 }
     55 #endif // ENCODER_MAP_ENABLE
     56 
     57 void dynamic_keymap_reset(void) {
     58     // Erase the keymaps, if necessary.
     59     nvm_dynamic_keymap_erase();
     60 
     61     // Reset the keymaps in EEPROM to what is in flash.
     62     for (int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++) {
     63         for (int row = 0; row < MATRIX_ROWS; row++) {
     64             for (int column = 0; column < MATRIX_COLS; column++) {
     65                 dynamic_keymap_set_keycode(layer, row, column, keycode_at_keymap_location_raw(layer, row, column));
     66             }
     67         }
     68 #ifdef ENCODER_MAP_ENABLE
     69         for (int encoder = 0; encoder < NUM_ENCODERS; encoder++) {
     70             dynamic_keymap_set_encoder(layer, encoder, true, keycode_at_encodermap_location_raw(layer, encoder, true));
     71             dynamic_keymap_set_encoder(layer, encoder, false, keycode_at_encodermap_location_raw(layer, encoder, false));
     72         }
     73 #endif // ENCODER_MAP_ENABLE
     74     }
     75 }
     76 
     77 void dynamic_keymap_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
     78     nvm_dynamic_keymap_read_buffer(offset, size, data);
     79 }
     80 
     81 void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
     82     nvm_dynamic_keymap_update_buffer(offset, size, data);
     83 }
     84 
     85 uint16_t keycode_at_keymap_location(uint8_t layer_num, uint8_t row, uint8_t column) {
     86     if (layer_num < DYNAMIC_KEYMAP_LAYER_COUNT && row < MATRIX_ROWS && column < MATRIX_COLS) {
     87         return dynamic_keymap_get_keycode(layer_num, row, column);
     88     }
     89     return KC_NO;
     90 }
     91 
     92 #ifdef ENCODER_MAP_ENABLE
     93 uint16_t keycode_at_encodermap_location(uint8_t layer_num, uint8_t encoder_idx, bool clockwise) {
     94     if (layer_num < DYNAMIC_KEYMAP_LAYER_COUNT && encoder_idx < NUM_ENCODERS) {
     95         return dynamic_keymap_get_encoder(layer_num, encoder_idx, clockwise);
     96     }
     97     return KC_NO;
     98 }
     99 #endif // ENCODER_MAP_ENABLE
    100 
    101 uint8_t dynamic_keymap_macro_get_count(void) {
    102     return DYNAMIC_KEYMAP_MACRO_COUNT;
    103 }
    104 
    105 uint16_t dynamic_keymap_macro_get_buffer_size(void) {
    106     return (uint16_t)nvm_dynamic_keymap_macro_size();
    107 }
    108 
    109 void dynamic_keymap_macro_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
    110     nvm_dynamic_keymap_macro_read_buffer(offset, size, data);
    111 }
    112 
    113 void dynamic_keymap_macro_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
    114     nvm_dynamic_keymap_macro_update_buffer(offset, size, data);
    115 }
    116 
    117 static uint8_t dynamic_keymap_read_byte(uint32_t offset) {
    118     uint8_t d;
    119     nvm_dynamic_keymap_macro_read_buffer(offset, 1, &d);
    120     return d;
    121 }
    122 
    123 typedef struct send_string_nvm_state_t {
    124     uint32_t offset;
    125 } send_string_nvm_state_t;
    126 
    127 char send_string_get_next_nvm(void *arg) {
    128     send_string_nvm_state_t *state = (send_string_nvm_state_t *)arg;
    129     char                     ret   = dynamic_keymap_read_byte(state->offset);
    130     state->offset++;
    131     return ret;
    132 }
    133 
    134 void dynamic_keymap_macro_reset(void) {
    135     // Erase the macros, if necessary.
    136     nvm_dynamic_keymap_macro_erase();
    137     nvm_dynamic_keymap_macro_reset();
    138 }
    139 
    140 void dynamic_keymap_macro_send(uint8_t id) {
    141     if (id >= DYNAMIC_KEYMAP_MACRO_COUNT) {
    142         return;
    143     }
    144 
    145     // Check the last byte of the buffer.
    146     // If it's not zero, then we are in the middle
    147     // of buffer writing, possibly an aborted buffer
    148     // write. So do nothing.
    149     if (dynamic_keymap_read_byte(nvm_dynamic_keymap_macro_size() - 1) != 0) {
    150         return;
    151     }
    152 
    153     // Skip N null characters
    154     // p will then point to the Nth macro
    155     uint32_t offset = 0;
    156     uint32_t end    = nvm_dynamic_keymap_macro_size();
    157     while (id > 0) {
    158         // If we are past the end of the buffer, then there is
    159         // no Nth macro in the buffer.
    160         if (offset == end) {
    161             return;
    162         }
    163         if (dynamic_keymap_read_byte(offset) == 0) {
    164             --id;
    165         }
    166         ++offset;
    167     }
    168 
    169     send_string_nvm_state_t state = {.offset = offset};
    170     send_string_with_delay_impl(send_string_get_next_nvm, &state, DYNAMIC_KEYMAP_MACRO_DELAY);
    171 }