diff options
Diffstat (limited to 'quantum')
32 files changed, 1166 insertions, 233 deletions
diff --git a/quantum/action.c b/quantum/action.c index 3efed443a3..60301fa606 100644 --- a/quantum/action.c +++ b/quantum/action.c @@ -14,9 +14,18 @@ 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 <http://www.gnu.org/licenses/>. */ +#include <limits.h> + +#ifdef DEBUG_ACTION +# include "debug.h" +#else +# include "nodebug.h" +#endif + #include "host.h" #include "keycode.h" #include "keyboard.h" +#include "keymap.h" #include "mousekey.h" #include "programmable_button.h" #include "command.h" @@ -32,12 +41,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. # include "backlight.h" #endif -#ifdef DEBUG_ACTION -# include "debug.h" -#else -# include "nodebug.h" -#endif - #ifdef POINTING_DEVICE_ENABLE # include "pointing_device.h" #endif @@ -89,6 +92,7 @@ void action_exec(keyevent_t event) { } #ifdef SWAP_HANDS_ENABLE + // Swap hands handles both keys and encoders, if ENCODER_MAP_ENABLE is defined. if (!IS_NOEVENT(event)) { process_hand_swap(&event); } @@ -136,27 +140,65 @@ void action_exec(keyevent_t event) { } #ifdef SWAP_HANDS_ENABLE +extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS]; +# ifdef ENCODER_MAP_ENABLE +extern const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS]; +# endif // ENCODER_MAP_ENABLE + bool swap_hands = false; bool swap_held = false; +bool should_swap_hands(size_t index, uint8_t *swap_state, bool pressed) { + size_t array_index = index / (CHAR_BIT); + size_t bit_index = index % (CHAR_BIT); + uint8_t bit_val = 1 << bit_index; + bool do_swap = pressed ? swap_hands : swap_state[array_index] & bit_val; + return do_swap; +} + +void set_swap_hands_state(size_t index, uint8_t *swap_state, bool on) { + size_t array_index = index / (CHAR_BIT); + size_t bit_index = index % (CHAR_BIT); + uint8_t bit_val = 1 << bit_index; + if (on) { + swap_state[array_index] |= bit_val; + } else { + swap_state[array_index] &= ~bit_val; + } +} + /** \brief Process Hand Swap * * FIXME: Needs documentation. */ void process_hand_swap(keyevent_t *event) { - static swap_state_row_t swap_state[MATRIX_ROWS]; - - keypos_t pos = event->key; - swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col; - bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit); - - if (do_swap) { - event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); - event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); - swap_state[pos.row] |= col_bit; - } else { - swap_state[pos.row] &= ~(col_bit); + keypos_t pos = event->key; + if (pos.row < MATRIX_ROWS && pos.col < MATRIX_COLS) { + static uint8_t matrix_swap_state[((MATRIX_ROWS * MATRIX_COLS) + (CHAR_BIT)-1) / (CHAR_BIT)]; + size_t index = (size_t)(pos.row * MATRIX_COLS) + pos.col; + bool do_swap = should_swap_hands(index, matrix_swap_state, event->pressed); + if (do_swap) { + event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); + event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); + set_swap_hands_state(index, matrix_swap_state, true); + } else { + set_swap_hands_state(index, matrix_swap_state, false); + } + } +# ifdef ENCODER_MAP_ENABLE + else if (pos.row == KEYLOC_ENCODER_CW || pos.row == KEYLOC_ENCODER_CCW) { + static uint8_t encoder_swap_state[((NUM_ENCODERS) + (CHAR_BIT)-1) / (CHAR_BIT)]; + size_t index = pos.col; + bool do_swap = should_swap_hands(index, encoder_swap_state, event->pressed); + if (do_swap) { + event->key.row = pos.row; + event->key.col = pgm_read_byte(&encoder_hand_swap_config[pos.col]); + set_swap_hands_state(index, encoder_swap_state, true); + } else { + set_swap_hands_state(index, encoder_swap_state, false); + } } +# endif // ENCODER_MAP_ENABLE } #endif diff --git a/quantum/action_layer.c b/quantum/action_layer.c index e20eedee40..473e0e948d 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -1,8 +1,5 @@ +#include <limits.h> #include <stdint.h> -#include "keyboard.h" -#include "action.h" -#include "util.h" -#include "action_layer.h" #ifdef DEBUG_ACTION # include "debug.h" @@ -10,6 +7,12 @@ # include "nodebug.h" #endif +#include "keyboard.h" +#include "keymap.h" +#include "action.h" +#include "util.h" +#include "action_layer.h" + /** \brief Default Layer State */ layer_state_t default_layer_state = 0; @@ -223,19 +226,20 @@ void layer_debug(void) { /** \brief source layer cache */ -uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; +uint8_t source_layers_cache[((MATRIX_ROWS * MATRIX_COLS) + (CHAR_BIT)-1) / (CHAR_BIT)][MAX_LAYER_BITS] = {{0}}; +# ifdef ENCODER_MAP_ENABLE +uint8_t encoder_source_layers_cache[(NUM_ENCODERS + (CHAR_BIT)-1) / (CHAR_BIT)][MAX_LAYER_BITS] = {{0}}; +# endif // ENCODER_MAP_ENABLE -/** \brief update source layers cache +/** \brief update source layers cache impl * - * Updates the cached keys when changing layers + * Updates the supplied cache when changing layers */ -void update_source_layers_cache(keypos_t key, uint8_t layer) { - const uint8_t key_number = key.col + (key.row * MATRIX_COLS); - const uint8_t storage_row = key_number / 8; - const uint8_t storage_bit = key_number % 8; - +void update_source_layers_cache_impl(uint8_t layer, uint16_t entry_number, uint8_t cache[][MAX_LAYER_BITS]) { + const uint16_t storage_idx = entry_number / (CHAR_BIT); + const uint8_t storage_bit = entry_number % (CHAR_BIT); for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { - source_layers_cache[storage_row][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ source_layers_cache[storage_row][bit_number]) & (1U << storage_bit); + cache[storage_idx][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ cache[storage_idx][bit_number]) & (1U << storage_bit); } } @@ -243,18 +247,52 @@ void update_source_layers_cache(keypos_t key, uint8_t layer) { * * reads the cached keys stored when the layer was changed */ -uint8_t read_source_layers_cache(keypos_t key) { - const uint8_t key_number = key.col + (key.row * MATRIX_COLS); - const uint8_t storage_row = key_number / 8; - const uint8_t storage_bit = key_number % 8; - uint8_t layer = 0; +uint8_t read_source_layers_cache_impl(uint16_t entry_number, uint8_t cache[][MAX_LAYER_BITS]) { + const uint16_t storage_idx = entry_number / (CHAR_BIT); + const uint8_t storage_bit = entry_number % (CHAR_BIT); + uint8_t layer = 0; for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { - layer |= ((source_layers_cache[storage_row][bit_number] & (1U << storage_bit)) != 0) << bit_number; + layer |= ((cache[storage_idx][bit_number] & (1U << storage_bit)) != 0) << bit_number; } return layer; } + +/** \brief update encoder source layers cache + * + * Updates the cached encoders when changing layers + */ +void update_source_layers_cache(keypos_t key, uint8_t layer) { + if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { + const uint16_t entry_number = (uint16_t)(key.row * MATRIX_COLS) + key.col; + update_source_layers_cache_impl(layer, entry_number, source_layers_cache); + } +# ifdef ENCODER_MAP_ENABLE + else if (key.row == KEYLOC_ENCODER_CW || key.row == KEYLOC_ENCODER_CCW) { + const uint16_t entry_number = key.col; + update_source_layers_cache_impl(layer, entry_number, encoder_source_layers_cache); + } +# endif // ENCODER_MAP_ENABLE +} + +/** \brief read source layers cache + * + * reads the cached keys stored when the layer was changed + */ +uint8_t read_source_layers_cache(keypos_t key) { + if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { + const uint16_t entry_number = (uint16_t)(key.row * MATRIX_COLS) + key.col; + return read_source_layers_cache_impl(entry_number, source_layers_cache); + } +# ifdef ENCODER_MAP_ENABLE + else if (key.row == KEYLOC_ENCODER_CW || key.row == KEYLOC_ENCODER_CCW) { + const uint16_t entry_number = key.col; + return read_source_layers_cache_impl(entry_number, encoder_source_layers_cache); + } +# endif // ENCODER_MAP_ENABLE + return 0; +} #endif /** \brief Store or get action (FIXME: Needs better summary) diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c index 6f8b4f8c56..e436619428 100644 --- a/quantum/action_tapping.c +++ b/quantum/action_tapping.c @@ -1,10 +1,5 @@ #include <stdint.h> #include <stdbool.h> -#include "action.h" -#include "action_layer.h" -#include "action_tapping.h" -#include "keycode.h" -#include "timer.h" #ifdef DEBUG_ACTION # include "debug.h" @@ -12,6 +7,12 @@ # include "nodebug.h" #endif +#include "action.h" +#include "action_layer.h" +#include "action_tapping.h" +#include "keycode.h" +#include "timer.h" + #ifndef NO_ACTION_TAPPING # define IS_TAPPING() !IS_NOEVENT(tapping_key.event) diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index f070375ff3..fc1c55784d 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -21,6 +21,12 @@ #include "dynamic_keymap.h" #include "via.h" // for default VIA_EEPROM_ADDR_END +#ifdef ENCODER_ENABLE +# include "encoder.h" +#else +# define NUM_ENCODERS 0 +#endif + #ifndef DYNAMIC_KEYMAP_LAYER_COUNT # define DYNAMIC_KEYMAP_LAYER_COUNT 4 #endif @@ -58,20 +64,28 @@ # endif #endif -// Dynamic macro starts after dynamic keymaps -#ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR -# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2)) +// Dynamic encoders starts after dynamic keymaps +#ifndef DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR +# define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2)) #endif +// Dynamic macro starts after dynamic encoders, but only when using ENCODER_MAP +#ifdef ENCODER_MAP_ENABLE +# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2)) +# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +#else // ENCODER_MAP_ENABLE +# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) +# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +#endif // ENCODER_MAP_ENABLE + // Sanity check that dynamic keymaps fit in available EEPROM // If there's not 100 bytes available for macros, then something is wrong. // The keyboard should override DYNAMIC_KEYMAP_LAYER_COUNT to reduce it, // or DYNAMIC_KEYMAP_EEPROM_MAX_ADDR to increase it, *only if* the microcontroller has // more than the default. -#if DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR < 100 -# pragma message STR(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) " < 100" -# error Dynamic keymaps are configured to use more EEPROM than is available. -#endif +_Static_assert((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available."); // Dynamic macros are stored after the keymaps and use what is available // up to and including DYNAMIC_KEYMAP_EEPROM_MAX_ADDR. @@ -89,6 +103,7 @@ void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t c } uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return KC_NO; void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); // Big endian, so we can read/write EEPROM directly from host if we want uint16_t keycode = eeprom_read_byte(address) << 8; @@ -97,12 +112,36 @@ uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) } void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return; void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column); // Big endian, so we can read/write EEPROM directly from host if we want eeprom_update_byte(address, (uint8_t)(keycode >> 8)); eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF)); } +#ifdef ENCODER_MAP_ENABLE +void *dynamic_keymap_encoder_to_eeprom_address(uint8_t layer, uint8_t encoder_id) { + return ((void *)DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) + (layer * NUM_ENCODERS * 2 * 2) + (encoder_id * 2 * 2); +} + +uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return KC_NO; + void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); + // Big endian, so we can read/write EEPROM directly from host if we want + uint16_t keycode = ((uint16_t)eeprom_read_byte(address + (clockwise ? 0 : 2))) << 8; + keycode |= eeprom_read_byte(address + (clockwise ? 0 : 2) + 1); + return keycode; +} + +void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return; + void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); + // Big endian, so we can read/write EEPROM directly from host if we want + eeprom_update_byte(address + (clockwise ? 0 : 2), (uint8_t)(keycode >> 8)); + eeprom_update_byte(address + (clockwise ? 0 : 2) + 1, (uint8_t)(keycode & 0xFF)); +} +#endif // ENCODER_MAP_ENABLE + void dynamic_keymap_reset(void) { // Reset the keymaps in EEPROM to what is in flash. // All keyboards using dynamic keymaps should define a layout @@ -113,6 +152,12 @@ void dynamic_keymap_reset(void) { dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column])); } } +#ifdef ENCODER_MAP_ENABLE + for (int encoder = 0; encoder < NUM_ENCODERS; encoder++) { + dynamic_keymap_set_encoder(layer, encoder, true, pgm_read_word(&encoder_map[layer][encoder][0])); + dynamic_keymap_set_encoder(layer, encoder, false, pgm_read_word(&encoder_map[layer][encoder][1])); + } +#endif // ENCODER_MAP_ENABLE } } @@ -148,9 +193,15 @@ void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) { uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { return dynamic_keymap_get_keycode(layer, key.row, key.col); - } else { - return KC_NO; } +#ifdef ENCODER_MAP_ENABLE + else if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row == KEYLOC_ENCODER_CW && key.col < NUM_ENCODERS) { + return dynamic_keymap_get_encoder(layer, key.col, true); + } else if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row == KEYLOC_ENCODER_CCW && key.col < NUM_ENCODERS) { + return dynamic_keymap_get_encoder(layer, key.col, false); + } +#endif // ENCODER_MAP_ENABLE + return KC_NO; } 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); void * dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column); uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column); void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); -void dynamic_keymap_reset(void); +#ifdef ENCODER_MAP_ENABLE +uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise); +void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode); +#endif // ENCODER_MAP_ENABLE +void dynamic_keymap_reset(void); // These get/set the keycodes as stored in the EEPROM buffer // Data is big-endian 16-bit values (the keycodes) // Order is by layer/row/column diff --git a/quantum/encoder.c b/quantum/encoder.c index 438c7d8564..105bed0147 100644 --- a/quantum/encoder.c +++ b/quantum/encoder.c @@ -23,6 +23,10 @@ // for memcpy #include <string.h> +#ifndef ENCODER_MAP_KEY_DELAY +# define ENCODER_MAP_KEY_DELAY 2 +#endif + #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) # define ENCODER_RESOLUTION 4 #endif @@ -31,11 +35,13 @@ # error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B" #endif -#define NUMBER_OF_ENCODERS (sizeof(encoders_pad_a) / sizeof(pin_t)) -static pin_t encoders_pad_a[] = ENCODERS_PAD_A; -static pin_t encoders_pad_b[] = ENCODERS_PAD_B; +extern volatile bool isLeftHand; + +static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_A; +static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_B; + #ifdef ENCODER_RESOLUTIONS -static uint8_t encoder_resolutions[] = ENCODER_RESOLUTIONS; +static uint8_t encoder_resolutions[NUM_ENCODERS] = ENCODER_RESOLUTIONS; #endif #ifndef ENCODER_DIRECTION_FLIP @@ -47,18 +53,20 @@ static uint8_t encoder_resolutions[] = ENCODER_RESOLUTIONS; #endif static int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}; -static uint8_t encoder_state[NUMBER_OF_ENCODERS] = {0}; -static int8_t encoder_pulses[NUMBER_OF_ENCODERS] = {0}; +static uint8_t encoder_state[NUM_ENCODERS] = {0}; +static int8_t encoder_pulses[NUM_ENCODERS] = {0}; +// encoder counts +static uint8_t thisCount; #ifdef SPLIT_KEYBOARD -// right half encoders come over as second set of encoders -static uint8_t encoder_value[NUMBER_OF_ENCODERS * 2] = {0}; -// row offsets for each hand +// encoder offsets for each hand static uint8_t thisHand, thatHand; -#else -static uint8_t encoder_value[NUMBER_OF_ENCODERS] = {0}; +// encoder counts for each hand +static uint8_t thatCount; #endif +static uint8_t encoder_value[NUM_ENCODERS] = {0}; + __attribute__((weak)) void encoder_wait_pullup_charge(void) { wait_us(100); } @@ -72,46 +80,83 @@ __attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) { } void encoder_init(void) { +#ifdef SPLIT_KEYBOARD + thisHand = isLeftHand ? 0 : NUM_ENCODERS_LEFT; + thatHand = NUM_ENCODERS_LEFT - thisHand; + thisCount = isLeftHand ? NUM_ENCODERS_LEFT : NUM_ENCODERS_RIGHT; + thatCount = isLeftHand ? NUM_ENCODERS_RIGHT : NUM_ENCODERS_LEFT; +#else // SPLIT_KEYBOARD + thisCount = NUM_ENCODERS; +#endif + +#ifdef ENCODER_TESTS + // Annoying that we have to clear out values during initialisation here, but + // because all the arrays are static locals, rerunning tests in the same + // executable doesn't reset any of these. Kinda crappy having test-only code + // here, but it's the simplest solution. + memset(encoder_value, 0, sizeof(encoder_value)); + memset(encoder_state, 0, sizeof(encoder_state)); + memset(encoder_pulses, 0, sizeof(encoder_pulses)); + static const pin_t encoders_pad_a_left[] = ENCODERS_PAD_A; + static const pin_t encoders_pad_b_left[] = ENCODERS_PAD_B; + for (uint8_t i = 0; i < thisCount; i++) { + encoders_pad_a[i] = encoders_pad_a_left[i]; + encoders_pad_b[i] = encoders_pad_b_left[i]; + } +#endif + #if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) + // Re-initialise the pads if it's the right-hand side if (!isLeftHand) { - const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; - const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; -# if defined(ENCODER_RESOLUTIONS_RIGHT) - const uint8_t encoder_resolutions_right[] = ENCODER_RESOLUTIONS_RIGHT; -# endif - for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { + static const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; + static const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; + for (uint8_t i = 0; i < thisCount; i++) { encoders_pad_a[i] = encoders_pad_a_right[i]; encoders_pad_b[i] = encoders_pad_b_right[i]; -# if defined(ENCODER_RESOLUTIONS_RIGHT) - encoder_resolutions[i] = encoder_resolutions_right[i]; -# endif } } -#endif +#endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) - for (int i = 0; i < NUMBER_OF_ENCODERS; i++) { + // Encoder resolutions is handled purely master-side, so concatenate the two arrays +#if defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) +# if defined(ENCODER_RESOLUTIONS_RIGHT) + static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS_RIGHT; +# else // defined(ENCODER_RESOLUTIONS_RIGHT) + static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS; +# endif // defined(ENCODER_RESOLUTIONS_RIGHT) + for (uint8_t i = 0; i < NUM_ENCODERS_RIGHT; i++) { + encoder_resolutions[NUM_ENCODERS_LEFT + i] = encoder_resolutions_right[i]; + } +#endif // defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) + + for (uint8_t i = 0; i < thisCount; i++) { setPinInputHigh(encoders_pad_a[i]); setPinInputHigh(encoders_pad_b[i]); } encoder_wait_pullup_charge(); - for (int i = 0; i < NUMBER_OF_ENCODERS; i++) { + for (uint8_t i = 0; i < thisCount; i++) { encoder_state[i] = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1); } +} -#ifdef SPLIT_KEYBOARD - thisHand = isLeftHand ? 0 : NUMBER_OF_ENCODERS; - thatHand = NUMBER_OF_ENCODERS - thisHand; -#endif +#ifdef ENCODER_MAP_ENABLE +static void encoder_exec_mapping(uint8_t index, bool clockwise) { + // The delays below cater for Windows and its wonderful requirements. + action_exec(clockwise ? ENCODER_CW_EVENT(index, true) : ENCODER_CCW_EVENT(index, true)); + wait_ms(ENCODER_MAP_KEY_DELAY); + action_exec(clockwise ? ENCODER_CW_EVENT(index, false) : ENCODER_CCW_EVENT(index, false)); + wait_ms(ENCODER_MAP_KEY_DELAY); } +#endif // ENCODER_MAP_ENABLE static bool encoder_update(uint8_t index, uint8_t state) { bool changed = false; uint8_t i = index; #ifdef ENCODER_RESOLUTIONS - uint8_t resolution = encoder_resolutions[i]; + const uint8_t resolution = encoder_resolutions[i]; #else - uint8_t resolution = ENCODER_RESOLUTION; + const uint8_t resolution = ENCODER_RESOLUTION; #endif #ifdef SPLIT_KEYBOARD @@ -121,12 +166,20 @@ static bool encoder_update(uint8_t index, uint8_t state) { if (encoder_pulses[i] >= resolution) { encoder_value[index]++; changed = true; +#ifdef ENCODER_MAP_ENABLE + encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); +#else // ENCODER_MAP_ENABLE encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); +#endif // ENCODER_MAP_ENABLE } if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise encoder_value[index]--; changed = true; +#ifdef ENCODER_MAP_ENABLE + encoder_exec_mapping(index, ENCODER_CLOCKWISE); +#else // ENCODER_MAP_ENABLE encoder_update_kb(index, ENCODER_CLOCKWISE); +#endif // ENCODER_MAP_ENABLE } encoder_pulses[i] %= resolution; #ifdef ENCODER_DEFAULT_POS @@ -139,10 +192,13 @@ static bool encoder_update(uint8_t index, uint8_t state) { bool encoder_read(void) { bool changed = false; - for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { - encoder_state[i] <<= 2; - encoder_state[i] |= (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1); - changed |= encoder_update(i, encoder_state[i]); + for (uint8_t i = 0; i < thisCount; i++) { + uint8_t new_status = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1); + if ((encoder_state[i] & 0x3) != new_status) { + encoder_state[i] <<= 2; + encoder_state[i] |= new_status; + changed |= encoder_update(i, encoder_state[i]); + } } return changed; } @@ -150,26 +206,34 @@ bool encoder_read(void) { #ifdef SPLIT_KEYBOARD void last_encoder_activity_trigger(void); -void encoder_state_raw(uint8_t* slave_state) { - memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * NUMBER_OF_ENCODERS); +void encoder_state_raw(uint8_t *slave_state) { + memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * thisCount); } -void encoder_update_raw(uint8_t* slave_state) { +void encoder_update_raw(uint8_t *slave_state) { bool changed = false; - for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { - uint8_t index = i + thatHand; - int8_t delta = slave_state[i] - encoder_value[index]; + for (uint8_t i = 0; i < thatCount; i++) { // Note inverted logic -- we want the opposite side + const uint8_t index = i + thatHand; + int8_t delta = slave_state[i] - encoder_value[index]; while (delta > 0) { delta--; encoder_value[index]++; changed = true; +# ifdef ENCODER_MAP_ENABLE + encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); +# else // ENCODER_MAP_ENABLE encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); +# endif // ENCODER_MAP_ENABLE } while (delta < 0) { delta++; encoder_value[index]--; changed = true; +# ifdef ENCODER_MAP_ENABLE + encoder_exec_mapping(index, ENCODER_CLOCKWISE); +# else // ENCODER_MAP_ENABLE encoder_update_kb(index, ENCODER_CLOCKWISE); +# endif // ENCODER_MAP_ENABLE } } diff --git a/quantum/encoder.h b/quantum/encoder.h index 25dc77721d..82f95b4931 100644 --- a/quantum/encoder.h +++ b/quantum/encoder.h @@ -18,6 +18,7 @@ #pragma once #include "quantum.h" +#include "util.h" void encoder_init(void); bool encoder_read(void); @@ -26,6 +27,37 @@ bool encoder_update_kb(uint8_t index, bool clockwise); bool encoder_update_user(uint8_t index, bool clockwise); #ifdef SPLIT_KEYBOARD + void encoder_state_raw(uint8_t* slave_state); void encoder_update_raw(uint8_t* slave_state); -#endif + +# if defined(ENCODERS_PAD_A_RIGHT) +# define NUM_ENCODERS_LEFT (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t)) +# define NUM_ENCODERS_RIGHT (sizeof(((pin_t[])ENCODERS_PAD_A_RIGHT)) / sizeof(pin_t)) +# else +# define NUM_ENCODERS_LEFT (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t)) +# define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT +# endif +# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT) + +#else // SPLIT_KEYBOARD + +# define NUM_ENCODERS (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t)) +# define NUM_ENCODERS_LEFT NUM_ENCODERS +# define NUM_ENCODERS_RIGHT 0 + +#endif // SPLIT_KEYBOARD + +#ifndef NUM_ENCODERS +# define NUM_ENCODERS 0 +# define NUM_ENCODERS_LEFT 0 +# define NUM_ENCODERS_RIGHT 0 +#endif // NUM_ENCODERS + +#define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT) + +#ifdef ENCODER_MAP_ENABLE +# define ENCODER_CCW_CW(ccw, cw) \ + { (cw), (ccw) } |