diff options
| author | Nick Brassel <nick@tzarc.org> | 2022-03-09 19:29:00 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-09 19:29:00 +1100 |
| commit | 8d5eacb7dd76bfd45444ceb1efa9a9f840173552 (patch) | |
| tree | b6b8b641dd61f5de0c5b7ee1bf251f6a84043656 /quantum | |
| parent | 7121a228eb204a0d697c97503ac7a28b762ab598 (diff) | |
Add support for encoder mapping. (#13286)
Diffstat (limited to 'quantum')
| -rw-r--r-- | quantum/action.c | 65 | ||||
| -rw-r--r-- | quantum/action_layer.c | 67 | ||||
| -rw-r--r-- | quantum/dynamic_keymap.c | 50 | ||||
| -rw-r--r-- | quantum/dynamic_keymap.h | 6 | ||||
| -rw-r--r-- | quantum/encoder.c | 30 | ||||
| -rw-r--r-- | quantum/encoder.h | 6 | ||||
| -rw-r--r-- | quantum/keyboard.h | 36 | ||||
| -rw-r--r-- | quantum/keymap.h | 6 | ||||
| -rw-r--r-- | quantum/keymap_common.c | 13 | ||||
| -rw-r--r-- | quantum/process_keycode/process_combo.c | 11 |
10 files changed, 240 insertions, 50 deletions
diff --git a/quantum/action.c b/quantum/action.c index 3efed443a3..487218777e 100644 --- a/quantum/action.c +++ b/quantum/action.c | |||
| @@ -14,9 +14,11 @@ GNU General Public License for more details. | |||
| 14 | You should have received a copy of the GNU General Public License | 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/>. | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | */ | 16 | */ |
| 17 | #include <limits.h> | ||
| 17 | #include "host.h" | 18 | #include "host.h" |
| 18 | #include "keycode.h" | 19 | #include "keycode.h" |
| 19 | #include "keyboard.h" | 20 | #include "keyboard.h" |
| 21 | #include "keymap.h" | ||
| 20 | #include "mousekey.h" | 22 | #include "mousekey.h" |
| 21 | #include "programmable_button.h" | 23 | #include "programmable_button.h" |
| 22 | #include "command.h" | 24 | #include "command.h" |
| @@ -89,6 +91,7 @@ void action_exec(keyevent_t event) { | |||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | #ifdef SWAP_HANDS_ENABLE | 93 | #ifdef SWAP_HANDS_ENABLE |
| 94 | // Swap hands handles both keys and encoders, if ENCODER_MAP_ENABLE is defined. | ||
| 92 | if (!IS_NOEVENT(event)) { | 95 | if (!IS_NOEVENT(event)) { |
| 93 | process_hand_swap(&event); | 96 | process_hand_swap(&event); |
| 94 | } | 97 | } |
| @@ -136,27 +139,65 @@ void action_exec(keyevent_t event) { | |||
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | #ifdef SWAP_HANDS_ENABLE | 141 | #ifdef SWAP_HANDS_ENABLE |
| 142 | extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS]; | ||
| 143 | # ifdef ENCODER_MAP_ENABLE | ||
| 144 | extern const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS]; | ||
| 145 | # endif // ENCODER_MAP_ENABLE | ||
| 146 | |||
| 139 | bool swap_hands = false; | 147 | bool swap_hands = false; |
| 140 | bool swap_held = false; | 148 | bool swap_held = false; |
| 141 | 149 | ||
| 150 | bool should_swap_hands(size_t index, uint8_t *swap_state, bool pressed) { | ||
| 151 | size_t array_index = index / (CHAR_BIT); | ||
| 152 | size_t bit_index = index % (CHAR_BIT); | ||
| 153 | uint8_t bit_val = 1 << bit_index; | ||
| 154 | bool do_swap = pressed ? swap_hands : swap_state[array_index] & bit_val; | ||
| 155 | return do_swap; | ||
| 156 | } | ||
| 157 | |||
| 158 | void set_swap_hands_state(size_t index, uint8_t *swap_state, bool on) { | ||
| 159 | size_t array_index = index / (CHAR_BIT); | ||
| 160 | size_t bit_index = index % (CHAR_BIT); | ||
| 161 | uint8_t bit_val = 1 << bit_index; | ||
| 162 | if (on) { | ||
| 163 | swap_state[array_index] |= bit_val; | ||
| 164 | } else { | ||
| 165 | swap_state[array_index] &= ~bit_val; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 142 | /** \brief Process Hand Swap | 169 | /** \brief Process Hand Swap |
| 143 | * | 170 | * |
| 144 | * FIXME: Needs documentation. | 171 | * FIXME: Needs documentation. |
| 145 | */ | 172 | */ |
| 146 | void process_hand_swap(keyevent_t *event) { | 173 | void process_hand_swap(keyevent_t *event) { |
| 147 | static swap_state_row_t swap_state[MATRIX_ROWS]; | 174 | keypos_t pos = event->key; |
| 148 | 175 | if (pos.row < MATRIX_ROWS && pos.col < MATRIX_COLS) { | |
| 149 | keypos_t pos = event->key; | 176 | static uint8_t matrix_swap_state[((MATRIX_ROWS * MATRIX_COLS) + (CHAR_BIT)-1) / (CHAR_BIT)]; |
| 150 | swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col; | 177 | size_t index = (size_t)(pos.row * MATRIX_COLS) + pos.col; |
| 151 | bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit); | 178 | bool do_swap = should_swap_hands(index, matrix_swap_state, event->pressed); |
| 152 | 179 | if (do_swap) { | |
| 153 | if (do_swap) { | 180 | event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); |
| 154 | event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); | 181 | event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); |
| 155 | event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); | 182 | set_swap_hands_state(index, matrix_swap_state, true); |
| 156 | swap_state[pos.row] |= col_bit; | 183 | } else { |
| 157 | } else { | 184 | set_swap_hands_state(index, matrix_swap_state, false); |
| 158 | swap_state[pos.row] &= ~(col_bit); | 185 | } |
| 186 | } | ||
| 187 | # ifdef ENCODER_MAP_ENABLE | ||
| 188 | else if (pos.row == KEYLOC_ENCODER_CW || pos.row == KEYLOC_ENCODER_CCW) { | ||
| 189 | static uint8_t encoder_swap_state[((NUM_ENCODERS) + (CHAR_BIT)-1) / (CHAR_BIT)]; | ||
| 190 | size_t index = pos.col; | ||
| 191 | bool do_swap = should_swap_hands(index, encoder_swap_state, event->pressed); | ||
| 192 | if (do_swap) { | ||
| 193 | event->key.row = pos.row; | ||
| 194 | event->key.col = pgm_read_byte(&encoder_hand_swap_config[pos.col]); | ||
| 195 | set_swap_hands_state(index, encoder_swap_state, true); | ||
| 196 | } else { | ||
| 197 | set_swap_hands_state(index, encoder_swap_state, false); | ||
| 198 | } | ||
| 159 | } | 199 | } |
| 200 | # endif // ENCODER_MAP_ENABLE | ||
| 160 | } | 201 | } |
| 161 | #endif | 202 | #endif |
| 162 | 203 | ||
diff --git a/quantum/action_layer.c b/quantum/action_layer.c index e20eedee40..4d2921354b 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | #include <limits.h> | ||
| 1 | #include <stdint.h> | 2 | #include <stdint.h> |
| 2 | #include "keyboard.h" | 3 | #include "keyboard.h" |
| 4 | #include "keymap.h" | ||
| 3 | #include "action.h" | 5 | #include "action.h" |
| 4 | #include "util.h" | 6 | #include "util.h" |
| 5 | #include "action_layer.h" | 7 | #include "action_layer.h" |
| @@ -223,19 +225,20 @@ void layer_debug(void) { | |||
| 223 | /** \brief source layer cache | 225 | /** \brief source layer cache |
| 224 | */ | 226 | */ |
| 225 | 227 | ||
| 226 | uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; | 228 | uint8_t source_layers_cache[((MATRIX_ROWS * MATRIX_COLS) + (CHAR_BIT)-1) / (CHAR_BIT)][MAX_LAYER_BITS] = {{0}}; |
| 229 | # ifdef ENCODER_MAP_ENABLE | ||
| 230 | uint8_t encoder_source_layers_cache[(NUM_ENCODERS + (CHAR_BIT)-1) / (CHAR_BIT)][MAX_LAYER_BITS] = {{0}}; | ||
| 231 | # endif // ENCODER_MAP_ENABLE | ||
| 227 | 232 | ||
| 228 | /** \brief update source layers cache | 233 | /** \brief update source layers cache impl |
| 229 | * | 234 | * |
| 230 | * Updates the cached keys when changing layers | 235 | * Updates the supplied cache when changing layers |
| 231 | */ | 236 | */ |
| 232 | void update_source_layers_cache(keypos_t key, uint8_t layer) { | 237 | void update_source_layers_cache_impl(uint8_t layer, uint16_t entry_number, uint8_t cache[][MAX_LAYER_BITS]) { |
| 233 | const uint8_t key_number = key.col + (key.row * MATRIX_COLS); | 238 | const uint16_t storage_idx = entry_number / (CHAR_BIT); |
| 234 | const uint8_t storage_row = key_number / 8; | 239 | const uint8_t storage_bit = entry_number % (CHAR_BIT); |
| 235 | const uint8_t storage_bit = key_number % 8; | ||
| 236 | |||
| 237 | for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { | 240 | for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { |
| 238 | source_layers_cache[storage_row][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ source_layers_cache[storage_row][bit_number]) & (1U << storage_bit); | 241 | cache[storage_idx][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ cache[storage_idx][bit_number]) & (1U << storage_bit); |
| 239 | } | 242 | } |
| 240 | } | 243 | } |
| 241 | 244 | ||
| @@ -243,18 +246,52 @@ void update_source_layers_cache(keypos_t key, uint8_t layer) { | |||
| 243 | * | 246 | * |
| 244 | * reads the cached keys stored when the layer was changed | 247 | * reads the cached keys stored when the layer was changed |
| 245 | */ | 248 | */ |
| 246 | uint8_t read_source_layers_cache(keypos_t key) { | 249 | uint8_t read_source_layers_cache_impl(uint16_t entry_number, uint8_t cache[][MAX_LAYER_BITS]) { |
| 247 | const uint8_t key_number = key.col + (key.row * MATRIX_COLS); | 250 | const uint16_t storage_idx = entry_number / (CHAR_BIT); |
| 248 | const uint8_t storage_row = key_number / 8; | 251 | const uint8_t storage_bit = entry_number % (CHAR_BIT); |
| 249 | const uint8_t storage_bit = key_number % 8; | 252 | uint8_t layer = 0; |
| 250 | uint8_t layer = 0; | ||
| 251 | 253 | ||
| 252 | for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { | 254 | for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { |
| 253 | layer |= ((source_layers_cache[storage_row][bit_number] & (1U << storage_bit)) != 0) << bit_number; | 255 | layer |= ((cache[storage_idx][bit_number] & (1U << storage_bit)) != 0) << bit_number; |
| 254 | } | 256 | } |
| 255 | 257 | ||
| 256 | return layer; | 258 | return layer; |
| 257 | } | 259 | } |
| 260 | |||
| 261 | /** \brief update encoder source layers cache | ||
| 262 | * | ||
| 263 | * Updates the cached encoders when changing layers | ||
| 264 | */ | ||
| 265 | void update_source_layers_cache(keypos_t key, uint8_t layer) { | ||
| 266 | if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { | ||
| 267 | const uint16_t entry_number = (uint16_t)(key.row * MATRIX_COLS) + key.col; | ||
| 268 | update_source_layers_cache_impl(layer, entry_number, source_layers_cache); | ||
| 269 | } | ||
| 270 | # ifdef ENCODER_MAP_ENABLE | ||
| 271 | else if (key.row == KEYLOC_ENCODER_CW || key.row == KEYLOC_ENCODER_CCW) { | ||
| 272 | const uint16_t entry_number = key.col; | ||
| 273 | update_source_layers_cache_impl(layer, entry_number, encoder_source_layers_cache); | ||
| 274 | } | ||
| 275 | # endif // ENCODER_MAP_ENABLE | ||
| 276 | } | ||
| 277 | |||
| 278 | /** \brief read source layers cache | ||
| 279 | * | ||
| 280 | * reads the cached keys stored when the layer was changed | ||
| 281 | */ | ||
| 282 | uint8_t read_source_layers_cache(keypos_t key) { | ||
| 283 | if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { | ||
| 284 | const uint16_t entry_number = (uint16_t)(key.row * MATRIX_COLS) + key.col; | ||
| 285 | return read_source_layers_cache_impl(entry_number, source_layers_cache); | ||
| 286 | } | ||
| 287 | # ifdef ENCODER_MAP_ENABLE | ||
| 288 | else if (key.row == KEYLOC_ENCODER_CW || key.row == KEYLOC_ENCODER_CCW) { | ||
| 289 | const uint16_t entry_number = key.col; | ||
| 290 | return read_source_layers_cache_impl(entry_number, encoder_source_layers_cache); | ||
| 291 | } | ||
| 292 | # endif // ENCODER_MAP_ENABLE | ||
| 293 | return 0; | ||
| 294 | } | ||
| 258 | #endif | 295 | #endif |
| 259 | 296 | ||
| 260 | /** \brief Store or get action (FIXME: Needs better summary) | 297 | /** \brief Store or get action (FIXME: Needs better summary) |
diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index f070375ff3..c0859ca35f 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c | |||
| @@ -58,9 +58,14 @@ | |||
| 58 | # endif | 58 | # endif |
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| 61 | // Dynamic macro starts after dynamic keymaps | 61 | // Dynamic encoders starts after dynamic keymaps |
| 62 | #ifndef DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR | ||
| 63 | # define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2)) | ||
| 64 | #endif | ||
| 65 | |||
| 66 | // Dynamic macro starts after dynamic encoders | ||
| 62 | #ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR | 67 | #ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR |
| 63 | # define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2)) | 68 | # define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2)) |
| 64 | #endif | 69 | #endif |
| 65 | 70 | ||
| 66 | // Sanity check that dynamic keymaps fit in available EEPROM | 71 | // Sanity check that dynamic keymaps fit in available EEPROM |
| @@ -89,6 +94,7 @@ void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t c | |||
| 89 | } | 94 | } |
| 90 | 95 | ||
| 91 | uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) { | 96 | uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) { |
| 97 | if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return KC_NO; | ||
| 92 | void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); | 98 | void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); |
| 93 | // Big endian, so we can read/write EEPROM directly from host if we want | 99 | // Big endian, so we can read/write EEPROM directly from host if we want |
| 94 | uint16_t keycode = eeprom_read_byte(address) << 8; | 100 | uint16_t keycode = eeprom_read_byte(address) << 8; |
| @@ -97,12 +103,36 @@ uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) | |||
| 97 | } | 103 | } |
| 98 | 104 | ||
| 99 | void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) { | 105 | void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) { |
| 106 | if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return; | ||
| 100 | void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); | 107 | void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); |
| 101 | // Big endian, so we can read/write EEPROM directly from host if we want | 108 | // Big endian, so we can read/write EEPROM directly from host if we want |
| 102 | eeprom_update_byte(address, (uint8_t)(keycode >> 8)); | 109 | eeprom_update_byte(address, (uint8_t)(keycode >> 8)); |
| 103 | eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF)); | 110 | eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF)); |
| 104 | } | 111 | } |
| 105 | 112 | ||
| 113 | #ifdef ENCODER_MAP_ENABLE | ||
| 114 | void *dynamic_keymap_encoder_to_eeprom_address(uint8_t layer, uint8_t encoder_id) { | ||
| 115 | return ((void *)DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) + (layer * NUM_ENCODERS * 2 * 2) + (encoder_id * 2 * 2); | ||
| 116 | } | ||
| 117 | |||
| 118 | uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise) { | ||
| 119 | if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return KC_NO; | ||
| 120 | void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); | ||
| 121 | // Big endian, so we can read/write EEPROM directly from host if we want | ||
| 122 | uint16_t keycode = ((uint16_t)eeprom_read_byte(address + (clockwise ? 0 : 2))) << 8; | ||
| 123 | keycode |= eeprom_read_byte(address + (clockwise ? 0 : 2) + 1); | ||
| 124 | return keycode; | ||
| 125 | } | ||
| 126 | |||
| 127 | void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) { | ||
| 128 | if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return; | ||
| 129 | void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); | ||
| 130 | // Big endian, so we can read/write EEPROM directly from host if we want | ||
| 131 | eeprom_update_byte(address + (clockwise ? 0 : 2), (uint8_t)(keycode >> 8)); | ||
| 132 | eeprom_update_byte(address + (clockwise ? 0 : 2) + 1, (uint8_t)(keycode & 0xFF)); | ||
| 133 | } | ||
| 134 | #endif // ENCODER_MAP_ENABLE | ||
| 135 | |||
| 106 | void dynamic_keymap_reset(void) { | 136 | void dynamic_keymap_reset(void) { |
| 107 | // Reset the keymaps in EEPROM to what is in flash. | 137 | // Reset the keymaps in EEPROM to what is in flash. |
| 108 | // All keyboards using dynamic keymaps should define a layout | 138 | // All keyboards using dynamic keymaps should define a layout |
| @@ -113,6 +143,12 @@ void dynamic_keymap_reset(void) { | |||
| 113 | dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column])); | 143 | dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column])); |
| 114 | } | 144 | } |
| 115 | } | 145 | } |
| 146 | #ifdef ENCODER_MAP_ENABLE | ||
| 147 | for (int encoder = 0; encoder < NUM_ENCODERS; encoder++) { | ||
| 148 | dynamic_keymap_set_encoder(layer, encoder, true, pgm_read_word(&encoder_map[layer][encoder][0])); | ||
| 149 | dynamic_keymap_set_encoder(layer, encoder, false, pgm_read_word(&encoder_map[layer][encoder][1])); | ||
| 150 | } | ||
| 151 | #endif // ENCODER_MAP_ENABLE | ||
| 116 | } | 152 | } |
| 117 | } | 153 | } |
| 118 | 154 | ||
| @@ -148,9 +184,15 @@ void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) { | |||
| 148 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { | 184 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { |
| 149 | if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { | 185 | if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { |
| 150 | return dynamic_keymap_get_keycode(layer, key.row, key.col); | 186 | return dynamic_keymap_get_keycode(layer, key.row, key.col); |
| 151 | } else { | ||
| 152 | return KC_NO; | ||
| 153 | } | 187 | } |
| 188 | #ifdef ENCODER_MAP_ENABLE | ||
| 189 | else if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row == KEYLOC_ENCODER_CW && key.col < NUM_ENCODERS) { | ||
| 190 | return dynamic_keymap_get_encoder(layer, key.col, true); | ||
| 191 | } else if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row == KEYLOC_ENCODER_CCW && key.col < NUM_ENCODERS) { | ||
| 192 | return dynamic_keymap_get_encoder(layer, key.col, false); | ||
| 193 | } | ||
| 194 | #endif // ENCODER_MAP_ENABLE | ||
| 195 | return KC_NO; | ||
| 154 | } | 196 | } |
| 155 | 197 | ||
| 156 | uint8_t dynamic_keymap_macro_get_count(void) { | 198 | uint8_t dynamic_keymap_macro_get_count(void) { |
diff --git a/quantum/dynamic_keymap.h b/quantum/dynamic_keymap.h index 55676172b6..459b48d07a 100644 --- a/quantum/dynamic_keymap.h +++ b/quantum/dynamic_keymap.h | |||
| @@ -22,7 +22,11 @@ uint8_t dynamic_keymap_get_layer_count(void); | |||
| 22 | void * dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column); | 22 | void * dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column); |
| 23 | uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column); | 23 | uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column); |
| 24 | void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); | 24 | void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); |
| 25 | void dynamic_keymap_reset(void); | 25 | #ifdef ENCODER_MAP_ENABLE |
| 26 | uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise); | ||
| 27 | void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode); | ||
| 28 | #endif // ENCODER_MAP_ENABLE | ||
| 29 | void dynamic_keymap_reset(void); | ||
| 26 | // These get/set the keycodes as stored in the EEPROM buffer | 30 | // These get/set the keycodes as stored in the EEPROM buffer |
| 27 | // Data is big-endian 16-bit values (the keycodes) | 31 | // Data is big-endian 16-bit values (the keycodes) |
| 28 | // Order is by layer/row/column | 32 | // Order is by layer/row/column |
diff --git a/quantum/encoder.c b/quantum/encoder.c index 0a3d6f577c..105bed0147 100644 --- a/quantum/encoder.c +++ b/quantum/encoder.c | |||
| @@ -23,6 +23,10 @@ | |||
| 23 | // for memcpy | 23 | // for memcpy |
| 24 | #include <string.h> | 24 | #include <string.h> |
| 25 | 25 | ||
| 26 | #ifndef ENCODER_MAP_KEY_DELAY | ||
| 27 | # define ENCODER_MAP_KEY_DELAY 2 | ||
| 28 | #endif | ||
| 29 | |||
| 26 | #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) | 30 | #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) |
| 27 | # define ENCODER_RESOLUTION 4 | 31 | # define ENCODER_RESOLUTION 4 |
| 28 | #endif | 32 | #endif |
| @@ -135,6 +139,16 @@ void encoder_init(void) { | |||
| 135 | } | 139 | } |
| 136 | } | 140 | } |
| 137 | 141 | ||
| 142 | #ifdef ENCODER_MAP_ENABLE | ||
| 143 | static void encoder_exec_mapping(uint8_t index, bool clockwise) { | ||
| 144 | // The delays below cater for Windows and its wonderful requirements. | ||
| 145 | action_exec(clockwise ? ENCODER_CW_EVENT(index, true) : ENCODER_CCW_EVENT(index, true)); | ||
| 146 | wait_ms(ENCODER_MAP_KEY_DELAY); | ||
| 147 | action_exec(clockwise ? ENCODER_CW_EVENT(index, false) : ENCODER_CCW_EVENT(index, false)); | ||
| 148 | wait_ms(ENCODER_MAP_KEY_DELAY); | ||
| 149 | } | ||
| 150 | #endif // ENCODER_MAP_ENABLE | ||
| 151 | |||
| 138 | static bool encoder_update(uint8_t index, uint8_t state) { | 152 | static bool encoder_update(uint8_t index, uint8_t state) { |
| 139 | bool changed = false; | 153 | bool changed = false; |
| 140 | uint8_t i = index; | 154 | uint8_t i = index; |
| @@ -152,12 +166,20 @@ static bool encoder_update(uint8_t index, uint8_t state) { | |||
| 152 | if (encoder_pulses[i] >= resolution) { | 166 | if (encoder_pulses[i] >= resolution) { |
| 153 | encoder_value[index]++; | 167 | encoder_value[index]++; |
| 154 | changed = true; | 168 | changed = true; |
| 169 | #ifdef ENCODER_MAP_ENABLE | ||
| 170 | encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); | ||
| 171 | #else // ENCODER_MAP_ENABLE | ||
| 155 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); | 172 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); |
| 173 | #endif // ENCODER_MAP_ENABLE | ||
| 156 | } | 174 | } |
| 157 | if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise | 175 | if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise |
| 158 | encoder_value[index]--; | 176 | encoder_value[index]--; |
| 159 | changed = true; | 177 | changed = true; |
| 178 | #ifdef ENCODER_MAP_ENABLE | ||
| 179 | encoder_exec_mapping(index, ENCODER_CLOCKWISE); | ||
| 180 | #else // ENCODER_MAP_ENABLE | ||
| 160 | encoder_update_kb(index, ENCODER_CLOCKWISE); | 181 | encoder_update_kb(index, ENCODER_CLOCKWISE); |
| 182 | #endif // ENCODER_MAP_ENABLE | ||
| 161 | } | 183 | } |
| 162 | encoder_pulses[i] %= resolution; | 184 | encoder_pulses[i] %= resolution; |
| 163 | #ifdef ENCODER_DEFAULT_POS | 185 | #ifdef ENCODER_DEFAULT_POS |
| @@ -197,13 +219,21 @@ void encoder_update_raw(uint8_t *slave_state) { | |||
| 197 | delta--; | 219 | delta--; |
| 198 | encoder_value[index]++; | 220 | encoder_value[index]++; |
| 199 | changed = true; | 221 | changed = true; |
| 222 | # ifdef ENCODER_MAP_ENABLE | ||
| 223 | encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); | ||
| 224 | # else // ENCODER_MAP_ENABLE | ||
| 200 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); | 225 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); |
| 226 | # endif // ENCODER_MAP_ENABLE | ||
| 201 | } | 227 | } |
| 202 | while (delta < 0) { | 228 | while (delta < 0) { |
| 203 | delta++; | 229 | delta++; |
| 204 | encoder_value[index]--; | 230 | encoder_value[index]--; |
| 205 | changed = true; | 231 | changed = true; |
| 232 | # ifdef ENCODER_MAP_ENABLE | ||
| 233 | encoder_exec_mapping(index, ENCODER_CLOCKWISE); | ||
| 234 | # else // ENCODER_MAP_ENABLE | ||
| 206 | encoder_update_kb(index, ENCODER_CLOCKWISE); | 235 | encoder_update_kb(index, ENCODER_CLOCKWISE); |
| 236 | # endif // ENCODER_MAP_ENABLE | ||
| 207 | } | 237 | } |
| 208 | } | 238 | } |
| 209 | 239 | ||
diff --git a/quantum/encoder.h b/quantum/encoder.h index dd6db14629..82f95b4931 100644 --- a/quantum/encoder.h +++ b/quantum/encoder.h | |||
| @@ -55,3 +55,9 @@ void encoder_update_raw(uint8_t* slave_state); | |||
| 55 | #endif // NUM_ENCODERS | 55 | #endif // NUM_ENCODERS |
| 56 | 56 | ||
| 57 | #define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT) | 57 | #define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT) |
| 58 | |||
| 59 | #ifdef ENCODER_MAP_ENABLE | ||
| 60 | # define ENCODER_CCW_CW(ccw, cw) \ | ||
| 61 | { (cw), (ccw) } | ||
| 62 | extern const uint16_t encoder_map[][NUM_ENCODERS][2]; | ||
| 63 | #endif // ENCODER_MAP_ENABLE | ||
diff --git a/quantum/keyboard.h b/quantum/keyboard.h index e122b38264..62661596c1 100644 --- a/quantum/keyboard.h +++ b/quantum/keyboard.h | |||
| @@ -40,25 +40,47 @@ typedef struct { | |||
| 40 | /* equivalent test of keypos_t */ | 40 | /* equivalent test of keypos_t */ |
| 41 | #define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) | 41 | #define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) |
| 42 | 42 | ||
| 43 | /* special keypos_t entries */ | ||
| 44 | #define KEYLOC_TICK 255 | ||
| 45 | #define KEYLOC_COMBO 254 | ||
| 46 | #define KEYLOC_ENCODER_CW 253 | ||
| 47 | #define KEYLOC_ENCODER_CCW 252 | ||
| 48 | |||
| 43 | /* Rules for No Event: | 49 | /* Rules for No Event: |
| 44 | * 1) (time == 0) to handle (keyevent_t){} as empty event | 50 | * 1) (time == 0) to handle (keyevent_t){} as empty event |
| 45 | * 2) Matrix(255, 255) to make TICK event available | 51 | * 2) Matrix(255, 255) to make TICK event available |
| 46 | */ | 52 | */ |
| 47 | static inline bool IS_NOEVENT(keyevent_t event) { | 53 | static inline bool IS_NOEVENT(keyevent_t event) { |
| 48 | return event.time == 0 || (event.key.row == 255 && event.key.col == 255); | 54 | return event.time == 0 || (event.key.row == KEYLOC_TICK && event.key.col == KEYLOC_TICK); |
| 55 | } | ||
| 56 | static inline bool IS_KEYEVENT(keyevent_t event) { | ||
| 57 | return event.key.row < MATRIX_ROWS && event.key.col < MATRIX_COLS; | ||
| 58 | } | ||
| 59 | static inline bool IS_COMBOEVENT(keyevent_t event) { | ||
| 60 | return event.key.row == KEYLOC_COMBO; | ||
| 61 | } | ||
| 62 | static inline bool IS_ENCODEREVENT(keyevent_t event) { | ||
| 63 | return event.key.row == KEYLOC_ENCODER_CW || event.key.row == KEYLOC_ENCODER_CCW; | ||
| 49 | } | 64 | } |
| 50 | static inline bool IS_PRESSED(keyevent_t event) { | 65 | static inline bool IS_PRESSED(keyevent_t event) { |
| 51 | return (!IS_NOEVENT(event) && event.pressed); | 66 | return !IS_NOEVENT(event) && event.pressed; |
| 52 | } | 67 | } |
| 53 | static inline bool IS_RELEASED(keyevent_t event) { | 68 | static inline bool IS_RELEASED(keyevent_t event) { |
| 54 | return (!IS_NOEVENT(event) && !event.pressed); | 69 | return !IS_NOEVENT(event) && !event.pressed; |
| 55 | } | 70 | } |
| 56 | 71 | ||
| 72 | /* Common keyevent object factory */ | ||
| 73 | #define MAKE_KEYPOS(row_num, col_num) ((keypos_t){.row = (row_num), .col = (col_num)}) | ||
| 74 | #define MAKE_KEYEVENT(row_num, col_num, press) ((keyevent_t){.key = MAKE_KEYPOS((row_num), (col_num)), .pressed = (press), .time = (timer_read() | 1)}) | ||
| 75 | |||
| 57 | /* Tick event */ | 76 | /* Tick event */ |
| 58 | #define TICK \ | 77 | #define TICK MAKE_KEYEVENT(KEYLOC_TICK, KEYLOC_TICK, false) |
| 59 | (keyevent_t) { \ | 78 | |
| 60 | .key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) \ | 79 | #ifdef ENCODER_MAP_ENABLE |
| 61 | } | 80 | /* Encoder events */ |
| 81 | # define ENCODER_CW_EVENT(enc_id, press) MAKE_KEYEVENT(KEYLOC_ENCODER_CW, (enc_id), (press)) | ||
| 82 | # define ENCODER_CCW_EVENT(enc_id, press) MAKE_KEYEVENT(KEYLOC_ENCODER_CCW, (enc_id), (press)) | ||
| 83 | #endif // ENCODER_MAP_ENABLE | ||
| 62 | 84 | ||
| 63 | /* it runs once at early stage of startup before keyboard_init. */ | 85 | /* it runs once at early stage of startup before keyboard_init. */ |
| 64 | void keyboard_setup(void); | 86 | void keyboard_setup(void); |
diff --git a/quantum/keymap.h b/quantum/keymap.h index 2ee2e1b576..d64b271efb 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h | |||
| @@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 32 | // #include "print.h" | 32 | // #include "print.h" |
| 33 | #include "debug.h" | 33 | #include "debug.h" |
| 34 | #include "keycode_config.h" | 34 | #include "keycode_config.h" |
| 35 | #include "gpio.h" // for pin_t | ||
| 35 | 36 | ||
| 36 | // ChibiOS uses RESET in its FlagStatus enumeration | 37 | // ChibiOS uses RESET in its FlagStatus enumeration |
| 37 | // Therefore define it as QK_BOOTLOADER here, to avoid name collision | 38 | // Therefore define it as QK_BOOTLOADER here, to avoid name collision |
| @@ -49,3 +50,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 49 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); | 50 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); |
| 50 | 51 | ||
| 51 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | 52 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; |
| 53 | |||
| 54 | #ifdef ENCODER_MAP_ENABLE | ||
| 55 | // Ensure we have a forward declaration for the encoder map | ||
| 56 | # include "encoder.h" | ||
| 57 | #endif | ||
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c index a91b2a0b36..c1940f0fd3 100644 --- a/quantum/keymap_common.c +++ b/quantum/keymap_common.c | |||
| @@ -148,6 +148,15 @@ action_t action_for_keycode(uint16_t keycode) { | |||
| 148 | 148 | ||
| 149 | // translates key to keycode | 149 | // translates key to keycode |
| 150 | __attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { | 150 | __attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { |
| 151 | // Read entire word (16bits) | 151 | if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { |
| 152 | return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); | 152 | return pgm_read_word(&keymaps[layer][key.row][key.col]); |
| 153 | } | ||
| 154 | #ifdef ENCODER_MAP_ENABLE | ||
| 155 | else if (key.row == KEYLOC_ENCODER_CW && key.col < NUM_ENCODERS) { | ||
| 156 | return pgm_read_word(&encoder_map[layer][key.col][0]); | ||
| 157 | } else if (key.row == KEYLOC_ENCODER_CCW && key.col < NUM_ENCODERS) { | ||
| 158 | return pgm_read_word(&encoder_map[layer][key.col][1]); | ||
| 159 | } | ||
| 160 | #endif // ENCODER_MAP_ENABLE | ||
| 161 | return KC_NO; | ||
| 153 | } | 162 | } |
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c index efaf8fe0e9..d5a649adb3 100644 --- a/quantum/process_keycode/process_combo.c +++ b/quantum/process_keycode/process_combo.c | |||
| @@ -88,8 +88,6 @@ static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH]; | |||
| 88 | 88 | ||
| 89 | #define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH | 89 | #define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH |
| 90 | 90 | ||
| 91 | #define COMBO_KEY_POS ((keypos_t){.col = 254, .row = 254}) | ||
| 92 | |||
| 93 | #ifndef EXTRA_SHORT_COMBOS | 91 | #ifndef EXTRA_SHORT_COMBOS |
| 94 | /* flags are their own elements in combo_t struct. */ | 92 | /* flags are their own elements in combo_t struct. */ |
| 95 | # define COMBO_ACTIVE(combo) (combo->active) | 93 | # define COMBO_ACTIVE(combo) (combo->active) |
| @@ -140,12 +138,7 @@ static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH]; | |||
| 140 | static inline void release_combo(uint16_t combo_index, combo_t *combo) { | 138 | static inline void release_combo(uint16_t combo_index, combo_t *combo) { |
| 141 | if (combo->keycode) { | 139 | if (combo->keycode) { |
| 142 | keyrecord_t record = { | 140 | keyrecord_t record = { |
| 143 | .event = | 141 | .event = MAKE_KEYEVENT(KEYLOC_COMBO, KEYLOC_COMBO, false), |
| 144 | { | ||
| 145 | .key = COMBO_KEY_POS, | ||
| 146 | .time = timer_read() | 1, | ||
| 147 | .pressed = false, | ||
| 148 | }, | ||
| 149 | .keycode = combo->keycode, | 142 | .keycode = combo->keycode, |
| 150 | }; | 143 | }; |
| 151 | #ifndef NO_ACTION_TAPPING | 144 | #ifndef NO_ACTION_TAPPING |
| @@ -325,7 +318,7 @@ void apply_combo(uint16_t combo_index, combo_t *combo) { | |||
| 325 | if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) { | 318 | if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) { |
| 326 | // this in the end executes the combo when the key_buffer is dumped. | 319 | // this in the end executes the combo when the key_buffer is dumped. |
| 327 | record->keycode = combo->keycode; | 320 | record->keycode = combo->keycode; |
| 328 | record->event.key = COMBO_KEY_POS; | 321 | record->event.key = MAKE_KEYPOS(KEYLOC_COMBO, KEYLOC_COMBO); |
| 329 | 322 | ||
| 330 | qrecord->combo_index = combo_index; | 323 | qrecord->combo_index = combo_index; |
| 331 | ACTIVATE_COMBO(combo); | 324 | ACTIVATE_COMBO(combo); |
