]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/dynamic_keymap.c
[Keymap] Add missing tap dance action and fix RGB hues in personal keymaps (#6312)
[qmk_firmware.git] / quantum / dynamic_keymap.c
1 /* Copyright 2017 Jason Williams (Wilba)
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include "config.h"
18 #include "keymap.h" // to get keymaps[][][]
19 #include "tmk_core/common/eeprom.h"
20 #include "progmem.h" // to read default from flash
21 #include "quantum.h" // for send_string()
22 #include "dynamic_keymap.h"
23
24 #ifdef DYNAMIC_KEYMAP_ENABLE
25
26 #ifndef DYNAMIC_KEYMAP_EEPROM_ADDR
27 #error DYNAMIC_KEYMAP_EEPROM_ADDR not defined
28 #endif
29
30 #ifndef DYNAMIC_KEYMAP_LAYER_COUNT
31 #error DYNAMIC_KEYMAP_LAYER_COUNT not defined
32 #endif
33
34 #ifndef DYNAMIC_KEYMAP_MACRO_COUNT
35 #error DYNAMIC_KEYMAP_MACRO_COUNT not defined
36 #endif
37
38 #ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
39 #error DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR not defined
40 #endif
41
42 #ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE
43 #error DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE not defined
44 #endif
45
46 uint8_t dynamic_keymap_get_layer_count(void)
47 {
48         return DYNAMIC_KEYMAP_LAYER_COUNT;
49 }
50
51 void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column)
52 {
53         // TODO: optimize this with some left shifts
54         return ((void*)DYNAMIC_KEYMAP_EEPROM_ADDR) + ( layer * MATRIX_ROWS * MATRIX_COLS * 2 ) +
55                 ( row * MATRIX_COLS * 2 ) + ( column * 2 );
56 }
57
58 uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column)
59 {
60         void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
61         // Big endian, so we can read/write EEPROM directly from host if we want
62         uint16_t keycode = eeprom_read_byte(address) << 8;
63         keycode |= eeprom_read_byte(address + 1);
64         return keycode;
65 }
66
67 void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode)
68 {
69         void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
70         // Big endian, so we can read/write EEPROM directly from host if we want
71         eeprom_update_byte(address, (uint8_t)(keycode >> 8));
72         eeprom_update_byte(address+1, (uint8_t)(keycode & 0xFF));
73 }
74
75 void dynamic_keymap_reset(void)
76 {
77         // Reset the keymaps in EEPROM to what is in flash.
78         // All keyboards using dynamic keymaps should define a layout
79         // for the same number of layers as DYNAMIC_KEYMAP_LAYER_COUNT.
80         for ( int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++ )      {
81                 for ( int row = 0; row < MATRIX_ROWS; row++ ) {
82                         for ( int column = 0; column < MATRIX_COLS; column++ )  {
83                                 dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column]));
84                         }
85                 }
86         }
87 }
88
89 void dynamic_keymap_get_buffer( uint16_t offset, uint16_t size, uint8_t *data )
90 {
91         uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
92         void *source = (void*)(DYNAMIC_KEYMAP_EEPROM_ADDR+offset);
93         uint8_t *target = data;
94         for ( uint16_t i = 0; i < size; i++ ) {
95                 if ( offset + i < dynamic_keymap_eeprom_size ) {
96                         *target = eeprom_read_byte(source);
97                 } else {
98                         *target = 0x00;
99                 }
100                 source++;
101                 target++;
102         }
103 }
104
105 void dynamic_keymap_set_buffer( uint16_t offset, uint16_t size, uint8_t *data )
106 {
107         uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
108         void *target = (void*)(DYNAMIC_KEYMAP_EEPROM_ADDR+offset);
109         uint8_t *source = data;
110         for ( uint16_t i = 0; i < size; i++ ) {
111                 if ( offset + i < dynamic_keymap_eeprom_size ) {
112                         eeprom_update_byte(target, *source);
113                 }
114                 source++;
115                 target++;
116         }
117 }
118
119 // This overrides the one in quantum/keymap_common.c
120 uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
121 {
122         if ( layer < DYNAMIC_KEYMAP_LAYER_COUNT &&
123                         key.row < MATRIX_ROWS &&
124                         key.col < MATRIX_COLS ) {
125                 return dynamic_keymap_get_keycode(layer, key.row, key.col);
126         } else {
127                 return KC_NO;
128         }
129 }
130
131
132
133 uint8_t dynamic_keymap_macro_get_count(void)
134 {
135         return DYNAMIC_KEYMAP_MACRO_COUNT;
136 }
137
138 uint16_t dynamic_keymap_macro_get_buffer_size(void)
139 {
140         return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE;
141 }
142
143 void dynamic_keymap_macro_get_buffer( uint16_t offset, uint16_t size, uint8_t *data )
144 {
145         void *source = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+offset);
146         uint8_t *target = data;
147         for ( uint16_t i = 0; i < size; i++ ) {
148                 if ( offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE ) {
149                         *target = eeprom_read_byte(source);
150                 } else {
151                         *target = 0x00;
152                 }
153                 source++;
154                 target++;
155         }
156 }
157
158 void dynamic_keymap_macro_set_buffer( uint16_t offset, uint16_t size, uint8_t *data )
159 {
160         void *target = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+offset);
161         uint8_t *source = data;
162         for ( uint16_t i = 0; i < size; i++ ) {
163                 if ( offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE ) {
164                         eeprom_update_byte(target, *source);
165                 }
166                 source++;
167                 target++;
168         }
169 }
170
171 void dynamic_keymap_macro_reset(void)
172 {
173         void *p = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR);
174         void *end = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE);
175         while ( p != end ) {
176                 eeprom_update_byte(p, 0);
177                 ++p;
178         }
179 }
180
181 void dynamic_keymap_macro_send( uint8_t id )
182 {
183         if ( id >= DYNAMIC_KEYMAP_MACRO_COUNT ) {
184                 return;
185         }
186
187         // Check the last byte of the buffer.
188         // If it's not zero, then we are in the middle
189         // of buffer writing, possibly an aborted buffer
190         // write. So do nothing.
191         void *p = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE-1);
192         if ( eeprom_read_byte(p) != 0 ) {
193                 return;
194         }
195
196         // Skip N null characters
197         // p will then point to the Nth macro
198         p = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR);
199         void *end = (void*)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE);
200         while ( id > 0 ) {
201                 // If we are past the end of the buffer, then the buffer
202                 // contents are garbage, i.e. there were not DYNAMIC_KEYMAP_MACRO_COUNT
203                 // nulls in the buffer.
204                 if ( p == end ) {
205                         return;
206                 }
207                 if ( eeprom_read_byte(p) == 0 ) {
208                         --id;
209                 }
210                 ++p;
211         }
212
213         // Send the macro string one or two chars at a time
214         // by making temporary 1 or 2 char strings
215         char data[3] = { 0, 0, 0 };
216         // We already checked there was a null at the end of
217         // the buffer, so this cannot go past the end
218         while ( 1 ) {
219                 data[0] = eeprom_read_byte(p++);
220                 data[1] = 0;
221                 // Stop at the null terminator of this macro string
222                 if ( data[0] == 0 ) {
223                         break;
224                 }
225                 // If the char is magic (tap, down, up),
226                 // add the next char (key to use) and send a 2 char string.
227                 if ( data[0] == SS_TAP_CODE || data[0] == SS_DOWN_CODE || data[0] == SS_UP_CODE ) {
228                         data[1] = eeprom_read_byte(p++);
229                         if ( data[1] == 0 ) {
230                                 break;
231                         }
232                 }
233                 send_string(data);
234         }
235 }
236
237 #endif // DYNAMIC_KEYMAP_ENABLE
238