Merge remote-tracking branch 'qmk/master' into merge-2022-07-11
This commit is contained in:
commit
fde0c10bae
7121 changed files with 170388 additions and 28118 deletions
|
|
@ -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"
|
||||
|
|
@ -33,12 +42,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
|
||||
|
|
@ -90,6 +93,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);
|
||||
}
|
||||
|
|
@ -98,7 +102,7 @@ void action_exec(keyevent_t event) {
|
|||
keyrecord_t record = {.event = event};
|
||||
|
||||
#ifndef NO_ACTION_ONESHOT
|
||||
if (!keymap_config.oneshot_disable) {
|
||||
if (keymap_config.oneshot_enable) {
|
||||
if (QS_oneshot_timeout > 0) {
|
||||
if (has_oneshot_layer_timed_out()) {
|
||||
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
|
||||
|
|
@ -137,27 +141,65 @@ if (QS_oneshot_timeout > 0) {
|
|||
}
|
||||
|
||||
#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
|
||||
|
||||
|
|
@ -217,7 +259,7 @@ void process_record(keyrecord_t *record) {
|
|||
|
||||
if (!process_record_quantum(record)) {
|
||||
#ifndef NO_ACTION_ONESHOT
|
||||
if (is_oneshot_layer_active() && record->event.pressed && !keymap_config.oneshot_disable) {
|
||||
if (is_oneshot_layer_active() && record->event.pressed && keymap_config.oneshot_enable) {
|
||||
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -282,7 +324,7 @@ void process_action(keyrecord_t *record, action_t action) {
|
|||
# ifdef SWAP_HANDS_ENABLE
|
||||
&& !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)
|
||||
# endif
|
||||
&& !keymap_config.oneshot_disable) {
|
||||
&& keymap_config.oneshot_enable) {
|
||||
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
|
||||
do_release_oneshot = !is_oneshot_layer_active();
|
||||
}
|
||||
|
|
@ -326,7 +368,7 @@ void process_action(keyrecord_t *record, action_t action) {
|
|||
# ifndef NO_ACTION_ONESHOT
|
||||
case MODS_ONESHOT:
|
||||
// Oneshot modifier
|
||||
if (keymap_config.oneshot_disable) {
|
||||
if (!keymap_config.oneshot_enable) {
|
||||
if (event.pressed) {
|
||||
if (mods) {
|
||||
if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
|
||||
|
|
@ -362,7 +404,7 @@ void process_action(keyrecord_t *record, action_t action) {
|
|||
} else if (QS_oneshot_tap_toggle > 1 && tap_count == QS_oneshot_tap_toggle) {
|
||||
dprint("MODS_TAP: Toggling oneshot");
|
||||
clear_oneshot_mods();
|
||||
set_oneshot_locked_mods(mods);
|
||||
set_oneshot_locked_mods(mods | get_oneshot_locked_mods());
|
||||
register_mods(mods);
|
||||
} else {
|
||||
register_mods(mods | get_oneshot_mods());
|
||||
|
|
@ -375,8 +417,8 @@ void process_action(keyrecord_t *record, action_t action) {
|
|||
// Retain Oneshot mods
|
||||
if (QS_oneshot_tap_toggle > 1) {
|
||||
if (mods & get_mods()) {
|
||||
clear_oneshot_locked_mods();
|
||||
clear_oneshot_mods();
|
||||
set_oneshot_locked_mods(~mods & get_oneshot_locked_mods());
|
||||
unregister_mods(mods);
|
||||
}
|
||||
}
|
||||
|
|
@ -570,7 +612,7 @@ if (QS_oneshot_tap_toggle > 1) {
|
|||
# ifndef NO_ACTION_ONESHOT
|
||||
case OP_ONESHOT:
|
||||
// Oneshot modifier
|
||||
if (keymap_config.oneshot_disable) {
|
||||
if (!keymap_config.oneshot_enable) {
|
||||
if (event.pressed) {
|
||||
layer_on(action.layer_tap.val);
|
||||
} else {
|
||||
|
|
@ -580,7 +622,6 @@ if (QS_oneshot_tap_toggle > 1) {
|
|||
if (QS_oneshot_tap_toggle > 1) {
|
||||
do_release_oneshot = false;
|
||||
if (event.pressed) {
|
||||
del_mods(get_oneshot_locked_mods());
|
||||
if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
|
||||
reset_oneshot_layer();
|
||||
layer_off(action.layer_tap.val);
|
||||
|
|
@ -590,10 +631,8 @@ if (QS_oneshot_tap_toggle > 1) {
|
|||
set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
|
||||
}
|
||||
} else {
|
||||
add_mods(get_oneshot_locked_mods());
|
||||
if (tap_count >= QS_oneshot_tap_toggle) {
|
||||
reset_oneshot_layer();
|
||||
clear_oneshot_locked_mods();
|
||||
set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
|
||||
} else {
|
||||
clear_oneshot_layer_state(ONESHOT_PRESSED);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
#ifdef VIAL_ENABLE
|
||||
#include "vial.h"
|
||||
#endif
|
||||
|
|
@ -227,24 +230,58 @@ 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_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++) {
|
||||
cache[storage_idx][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ cache[storage_idx][bit_number]) & (1U << storage_bit);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief read source layers cache
|
||||
*
|
||||
* reads the cached keys stored when the layer was changed
|
||||
*/
|
||||
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 |= ((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) {
|
||||
#ifdef VIAL_ENABLE
|
||||
if (key.row == VIAL_MATRIX_MAGIC) return;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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
|
||||
|
|
@ -256,16 +293,17 @@ uint8_t read_source_layers_cache(keypos_t key) {
|
|||
if (key.row == VIAL_MATRIX_MAGIC) return 0;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
return layer;
|
||||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -23,17 +24,20 @@
|
|||
# else
|
||||
# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
|
||||
# endif
|
||||
# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < GET_TAPPING_TERM(get_record_keycode(&tapping_key, false), &tapping_key))
|
||||
|
||||
# ifdef DYNAMIC_TAPPING_TERM_ENABLE
|
||||
uint16_t g_tapping_term = TAPPING_TERM;
|
||||
|
||||
__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
|
||||
return g_tapping_term;
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef TAPPING_TERM_PER_KEY
|
||||
# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_record_keycode(&tapping_key, false), &tapping_key))
|
||||
# else
|
||||
# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < g_tapping_term)
|
||||
__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
|
||||
# ifdef DYNAMIC_TAPPING_TERM_ENABLE
|
||||
return g_tapping_term;
|
||||
# else
|
||||
return TAPPING_TERM;
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef TAPPING_FORCE_HOLD_PER_KEY
|
||||
|
|
@ -164,15 +168,7 @@ bool process_tapping(keyrecord_t *keyp) {
|
|||
else if (
|
||||
(
|
||||
(
|
||||
(
|
||||
# ifdef TAPPING_TERM_PER_KEY
|
||||
get_tapping_term(tapping_keycode, &tapping_key)
|
||||
# else
|
||||
g_tapping_term
|
||||
# endif
|
||||
>= 500
|
||||
)
|
||||
|
||||
GET_TAPPING_TERM(tapping_keycode, &tapping_key) >= 500
|
||||
# ifdef PERMISSIVE_HOLD_PER_KEY
|
||||
|| get_permissive_hold(tapping_keycode, &tapping_key)
|
||||
# elif defined(PERMISSIVE_HOLD)
|
||||
|
|
|
|||
|
|
@ -44,3 +44,11 @@ bool get_retro_tapping(uint16_t keycode, keyrecord_t *record);
|
|||
#ifdef DYNAMIC_TAPPING_TERM_ENABLE
|
||||
extern uint16_t g_tapping_term;
|
||||
#endif
|
||||
|
||||
#ifdef TAPPING_TERM_PER_KEY
|
||||
# define GET_TAPPING_TERM(keycode, record) get_tapping_term(keycode, record)
|
||||
#elif defined(DYNAMIC_TAPPING_TERM_ENABLE)
|
||||
# define GET_TAPPING_TERM(keycode, record) g_tapping_term
|
||||
#else
|
||||
# define GET_TAPPING_TERM(keycode, record) (TAPPING_TERM)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ void clear_oneshot_swaphands(void) {
|
|||
* FIXME: needs doc
|
||||
*/
|
||||
void set_oneshot_layer(uint8_t layer, uint8_t state) {
|
||||
if (!keymap_config.oneshot_disable) {
|
||||
if (keymap_config.oneshot_enable) {
|
||||
oneshot_layer_data = layer << 3 | state;
|
||||
layer_on(layer);
|
||||
oneshot_layer_time = timer_read();
|
||||
|
|
@ -169,7 +169,7 @@ void reset_oneshot_layer(void) {
|
|||
void clear_oneshot_layer_state(oneshot_fullfillment_t state) {
|
||||
uint8_t start_state = oneshot_layer_data;
|
||||
oneshot_layer_data &= ~state;
|
||||
if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) && !keymap_config.oneshot_disable) {
|
||||
if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) && keymap_config.oneshot_enable) {
|
||||
layer_off(get_oneshot_layer());
|
||||
reset_oneshot_layer();
|
||||
}
|
||||
|
|
@ -187,8 +187,8 @@ bool is_oneshot_layer_active(void) {
|
|||
* FIXME: needs doc
|
||||
*/
|
||||
void oneshot_set(bool active) {
|
||||
if (keymap_config.oneshot_disable != active) {
|
||||
keymap_config.oneshot_disable = active;
|
||||
if (keymap_config.oneshot_enable != active) {
|
||||
keymap_config.oneshot_enable = active;
|
||||
eeconfig_update_keymap(keymap_config.raw);
|
||||
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
|
||||
dprintf("Oneshot: active: %d\n", active);
|
||||
|
|
@ -200,7 +200,7 @@ void oneshot_set(bool active) {
|
|||
* FIXME: needs doc
|
||||
*/
|
||||
void oneshot_toggle(void) {
|
||||
oneshot_set(!keymap_config.oneshot_disable);
|
||||
oneshot_set(!keymap_config.oneshot_enable);
|
||||
}
|
||||
|
||||
/** \brief enable oneshot
|
||||
|
|
@ -220,7 +220,7 @@ void oneshot_disable(void) {
|
|||
}
|
||||
|
||||
bool is_oneshot_enabled(void) {
|
||||
return keymap_config.oneshot_disable;
|
||||
return keymap_config.oneshot_enable;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -392,7 +392,7 @@ void del_oneshot_mods(uint8_t mods) {
|
|||
* FIXME: needs doc
|
||||
*/
|
||||
void set_oneshot_mods(uint8_t mods) {
|
||||
if (!keymap_config.oneshot_disable) {
|
||||
if (keymap_config.oneshot_enable) {
|
||||
if (oneshot_mods != mods) {
|
||||
oneshot_time = timer_read();
|
||||
oneshot_mods = mods;
|
||||
|
|
|
|||
|
|
@ -405,14 +405,18 @@ ISR(TIMERx_OVF_vect)
|
|||
uint16_t interval = (uint16_t)get_breathing_period() * breathing_ISR_frequency / BREATHING_STEPS;
|
||||
// resetting after one period to prevent ugly reset at overflow.
|
||||
breathing_counter = (breathing_counter + 1) % (get_breathing_period() * breathing_ISR_frequency);
|
||||
uint8_t index = breathing_counter / interval % BREATHING_STEPS;
|
||||
uint8_t index = breathing_counter / interval;
|
||||
// limit index to max step value
|
||||
if (index >= BREATHING_STEPS) {
|
||||
index = BREATHING_STEPS - 1;
|
||||
}
|
||||
|
||||
if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) {
|
||||
breathing_interrupt_disable();
|
||||
}
|
||||
|
||||
// Set PWM to a brightnessvalue scaled to the configured resolution
|
||||
set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255))));
|
||||
set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint32_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255))));
|
||||
}
|
||||
|
||||
#endif // BACKLIGHT_BREATHING
|
||||
|
|
|
|||
80
quantum/caps_word.c
Normal file
80
quantum/caps_word.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021-2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "caps_word.h"
|
||||
|
||||
/** @brief True when Caps Word is active. */
|
||||
static bool caps_word_active = false;
|
||||
|
||||
#if CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
// Constrain timeout to a sensible range. With 16-bit timers, the longest
|
||||
// timeout possible is 32768 ms, rounded here to 30000 ms = half a minute.
|
||||
# if CAPS_WORD_IDLE_TIMEOUT < 100 || CAPS_WORD_IDLE_TIMEOUT > 30000
|
||||
# error "CAPS_WORD_IDLE_TIMEOUT must be between 100 and 30000 ms"
|
||||
# endif
|
||||
|
||||
/** @brief Deadline for idle timeout. */
|
||||
static uint16_t idle_timer = 0;
|
||||
|
||||
void caps_word_task(void) {
|
||||
if (caps_word_active && timer_expired(timer_read(), idle_timer)) {
|
||||
caps_word_off();
|
||||
}
|
||||
}
|
||||
|
||||
void caps_word_reset_idle_timer(void) {
|
||||
idle_timer = timer_read() + CAPS_WORD_IDLE_TIMEOUT;
|
||||
}
|
||||
#endif // CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
|
||||
void caps_word_on(void) {
|
||||
if (caps_word_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
clear_mods();
|
||||
#ifndef NO_ACTION_ONESHOT
|
||||
clear_oneshot_mods();
|
||||
#endif // NO_ACTION_ONESHOT
|
||||
#if CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
caps_word_reset_idle_timer();
|
||||
#endif // CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
|
||||
caps_word_active = true;
|
||||
caps_word_set_user(true);
|
||||
}
|
||||
|
||||
void caps_word_off(void) {
|
||||
if (!caps_word_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
unregister_weak_mods(MOD_MASK_SHIFT); // Make sure weak shift is off.
|
||||
caps_word_active = false;
|
||||
caps_word_set_user(false);
|
||||
}
|
||||
|
||||
void caps_word_toggle(void) {
|
||||
if (caps_word_active) {
|
||||
caps_word_off();
|
||||
} else {
|
||||
caps_word_on();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_caps_word_on(void) {
|
||||
return caps_word_active;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void caps_word_set_user(bool active) {}
|
||||
43
quantum/caps_word.h
Normal file
43
quantum/caps_word.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2021-2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
#ifndef CAPS_WORD_IDLE_TIMEOUT
|
||||
# define CAPS_WORD_IDLE_TIMEOUT 5000 // Default timeout of 5 seconds.
|
||||
#endif // CAPS_WORD_IDLE_TIMEOUT
|
||||
|
||||
#if CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
/** @brief Matrix scan task for Caps Word feature */
|
||||
void caps_word_task(void);
|
||||
|
||||
/** @brief Resets timer for Caps Word idle timeout. */
|
||||
void caps_word_reset_idle_timer(void);
|
||||
#else
|
||||
static inline void caps_word_task(void) {}
|
||||
#endif // CAPS_WORD_IDLE_TIMEOUT > 0
|
||||
|
||||
void caps_word_on(void); /**< Activates Caps Word. */
|
||||
void caps_word_off(void); /**< Deactivates Caps Word. */
|
||||
void caps_word_toggle(void); /**< Toggles Caps Word. */
|
||||
bool is_caps_word_on(void); /**< Gets whether currently active. */
|
||||
|
||||
/**
|
||||
* @brief Caps Word set callback.
|
||||
*
|
||||
* @param active True if Caps Word is active, false otherwise
|
||||
*/
|
||||
void caps_word_set_user(bool active);
|
||||
|
|
@ -26,6 +26,16 @@
|
|||
#include "vial.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENCODER_ENABLE
|
||||
# include "encoder.h"
|
||||
#else
|
||||
# define NUM_ENCODERS 0
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_LAYER_COUNT
|
||||
# define DYNAMIC_KEYMAP_LAYER_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_MACRO_COUNT
|
||||
# define DYNAMIC_KEYMAP_MACRO_COUNT 16
|
||||
#endif
|
||||
|
|
@ -116,6 +126,17 @@ static pin_t encoders_pad_a[] = ENCODERS_PAD_A;
|
|||
# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (VIAL_KEY_OVERRIDE_EEPROM_ADDR + VIAL_KEY_OVERRIDE_SIZE)
|
||||
#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,
|
||||
|
|
@ -139,9 +160,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;
|
||||
|
||||
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;
|
||||
|
|
@ -150,44 +169,35 @@ 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;
|
||||
|
||||
#ifdef VIAL_ENABLE
|
||||
if (keycode == RESET && !vial_unlocked)
|
||||
return;
|
||||
#endif
|
||||
|
||||
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 VIAL_ENCODERS_ENABLE
|
||||
static void *dynamic_keymap_encoder_to_eeprom_address(uint8_t layer, uint8_t idx, uint8_t dir) {
|
||||
return ((void *)VIAL_ENCODERS_EEPROM_ADDR) + (layer * NUMBER_OF_ENCODERS * 2 * 2) + (idx * 2 * 2) + dir * 2;
|
||||
#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 idx, uint8_t dir) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || idx >= NUMBER_OF_ENCODERS || dir > 1)
|
||||
return 0;
|
||||
|
||||
void *address = dynamic_keymap_encoder_to_eeprom_address(layer, idx, dir);
|
||||
uint16_t keycode = eeprom_read_byte(address) << 8;
|
||||
keycode |= eeprom_read_byte(address + 1);
|
||||
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 idx, uint8_t dir, uint16_t keycode) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || idx >= NUMBER_OF_ENCODERS || dir > 1)
|
||||
return;
|
||||
|
||||
void *address = dynamic_keymap_encoder_to_eeprom_address(layer, idx, dir);
|
||||
eeprom_update_byte(address, (uint8_t)(keycode >> 8));
|
||||
eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF));
|
||||
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
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
|
||||
#ifdef QMK_SETTINGS
|
||||
uint8_t dynamic_keymap_get_qmk_settings(uint16_t offset) {
|
||||
|
|
@ -273,12 +283,6 @@ int dynamic_keymap_set_key_override(uint8_t index, const vial_key_override_entry
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(VIAL_ENCODERS_ENABLE) && defined(VIAL_ENCODER_DEFAULT)
|
||||
static const uint16_t PROGMEM vial_encoder_default[] = VIAL_ENCODER_DEFAULT;
|
||||
_Static_assert(sizeof(vial_encoder_default)/sizeof(*vial_encoder_default) == 2 * DYNAMIC_KEYMAP_LAYER_COUNT * NUMBER_OF_ENCODERS,
|
||||
"There should be DYNAMIC_KEYMAP_LAYER_COUNT * NUMBER_OF_ENCODERS * 2 entries in the VIAL_ENCODER_DEFAULT array.");
|
||||
#endif
|
||||
|
||||
void dynamic_keymap_reset(void) {
|
||||
#ifdef VIAL_ENABLE
|
||||
/* temporarily unlock the keyboard so we can set hardcoded RESET keycode */
|
||||
|
|
@ -295,18 +299,12 @@ void dynamic_keymap_reset(void) {
|
|||
dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column]));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VIAL_ENCODERS_ENABLE
|
||||
for (int idx = 0; idx < NUMBER_OF_ENCODERS; ++idx) {
|
||||
#ifdef VIAL_ENCODER_DEFAULT
|
||||
dynamic_keymap_set_encoder(layer, idx, 0, pgm_read_word(&vial_encoder_default[2 * (layer * NUMBER_OF_ENCODERS + idx)]));
|
||||
dynamic_keymap_set_encoder(layer, idx, 1, pgm_read_word(&vial_encoder_default[2 * (layer * NUMBER_OF_ENCODERS + idx) + 1]));
|
||||
#else
|
||||
dynamic_keymap_set_encoder(layer, idx, 0, KC_TRNS);
|
||||
dynamic_keymap_set_encoder(layer, idx, 1, KC_TRNS);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#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
|
||||
}
|
||||
|
||||
#ifdef QMK_SETTINGS
|
||||
|
|
@ -428,9 +426,15 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ 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);
|
||||
#ifdef VIAL_ENCODERS_ENABLE
|
||||
uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t idx, uint8_t dir);
|
||||
void dynamic_keymap_set_encoder(uint8_t layer, uint8_t idx, uint8_t dir, uint16_t keycode);
|
||||
#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
|
||||
#ifdef QMK_SETTINGS
|
||||
uint8_t dynamic_keymap_get_qmk_settings(uint16_t offset);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ void eeconfig_init_quantum(void) {
|
|||
eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0);
|
||||
default_layer_state = 0;
|
||||
eeprom_update_byte(EECONFIG_KEYMAP_LOWER_BYTE, 0);
|
||||
eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, 0);
|
||||
eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, 0x4);
|
||||
eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
|
||||
eeprom_update_byte(EECONFIG_BACKLIGHT, 0);
|
||||
eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <stdbool.h>
|
||||
|
||||
#ifndef EECONFIG_MAGIC_NUMBER
|
||||
# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEE9 // When changing, decrement this value to avoid future re-init issues
|
||||
# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEE8 // When changing, decrement this value to avoid future re-init issues
|
||||
#endif
|
||||
#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -77,46 +85,83 @@ __attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) {
|
|||
#endif
|
||||
|
||||
void encoder_init(void) {
|
||||
#if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
|
||||
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++) {
|
||||
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
|
||||
}
|
||||
#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
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_ENCODERS; i++) {
|
||||
#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) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
#endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
|
||||
|
||||
// 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
|
||||
|
|
@ -126,12 +171,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
|
||||
|
|
@ -144,10 +197,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;
|
||||
}
|
||||
|
|
@ -155,26 +211,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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
extern const uint16_t encoder_map[][NUM_ENCODERS][2];
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
|
|
|
|||
22
quantum/encoder/tests/config_mock.h
Normal file
22
quantum/encoder/tests/config_mock.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1 }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
26
quantum/encoder/tests/config_mock_split_left_eq_right.h
Normal file
26
quantum/encoder/tests/config_mock_split_left_eq_right.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0, 2 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1, 3 }
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{ 4, 6 }
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{ 5, 7 }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock_split.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
26
quantum/encoder/tests/config_mock_split_left_gt_right.h
Normal file
26
quantum/encoder/tests/config_mock_split_left_gt_right.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0, 2, 4 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1, 3, 5 }
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{ 6, 8 }
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{ 7, 9 }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock_split.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
26
quantum/encoder/tests/config_mock_split_left_lt_right.h
Normal file
26
quantum/encoder/tests/config_mock_split_left_lt_right.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0, 2 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1, 3 }
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{ 4, 6, 8 }
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{ 5, 7, 9 }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock_split.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
26
quantum/encoder/tests/config_mock_split_no_left.h
Normal file
26
quantum/encoder/tests/config_mock_split_no_left.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{}
|
||||
#define ENCODERS_PAD_B \
|
||||
{}
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{ 0, 2 }
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{ 1, 3 }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock_split.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
26
quantum/encoder/tests/config_mock_split_no_right.h
Normal file
26
quantum/encoder/tests/config_mock_split_no_right.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0, 2 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1, 3 }
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{}
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mock_split.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
|
@ -30,12 +30,12 @@ struct update {
|
|||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t uidx = 0;
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
updates[uidx % 32] = {index, clockwise};
|
||||
uidx++;
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -47,15 +47,15 @@ bool setAndRead(pin_t pin, bool val) {
|
|||
class EncoderTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(EncoderTest, TestInit) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
EXPECT_EQ(updates_array_idx, 0);
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestOneClockwise) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(0, false);
|
||||
|
|
@ -63,26 +63,26 @@ TEST_F(EncoderTest, TestOneClockwise) {
|
|||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates_array_idx, 1);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestOneCounterClockwise) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, true);
|
||||
setAndRead(0, true);
|
||||
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates_array_idx, 1);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, false);
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestTwoClockwiseOneCC) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
|
|
@ -97,7 +97,7 @@ TEST_F(EncoderTest, TestTwoClockwiseOneCC) {
|
|||
setAndRead(1, true);
|
||||
setAndRead(0, true);
|
||||
|
||||
EXPECT_EQ(uidx, 3);
|
||||
EXPECT_EQ(updates_array_idx, 3);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
EXPECT_EQ(updates[1].index, 0);
|
||||
|
|
@ -107,38 +107,38 @@ TEST_F(EncoderTest, TestTwoClockwiseOneCC) {
|
|||
}
|
||||
|
||||
TEST_F(EncoderTest, TestNoEarly) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
// send 3 pulses. with resolution 4, that's not enough for a step.
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
EXPECT_EQ(updates_array_idx, 0);
|
||||
// now send last pulse
|
||||
setAndRead(1, true);
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates_array_idx, 1);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestHalfway) {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
encoder_init();
|
||||
// go halfway
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
EXPECT_EQ(updates_array_idx, 0);
|
||||
// back off
|
||||
setAndRead(1, true);
|
||||
setAndRead(0, true);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
EXPECT_EQ(updates_array_idx, 0);
|
||||
// go all the way
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
// should result in 1 update
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates_array_idx, 1);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
|
|
|||
135
quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
Normal file
135
quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* Copyright 2021 Balz Guenat
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* 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 "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "encoder.h"
|
||||
#include "encoder/tests/mock_split.h"
|
||||
}
|
||||
|
||||
struct update {
|
||||
int8_t index;
|
||||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool isLeftHand;
|
||||
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
if (!isLeftHand) {
|
||||
// this method has no effect on slave half
|
||||
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
|
||||
return true;
|
||||
}
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setAndRead(pin_t pin, bool val) {
|
||||
setPin(pin, val);
|
||||
return encoder_read();
|
||||
}
|
||||
|
||||
class EncoderSplitTestLeftEqRight : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
updates_array_idx = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
pinIsInputHigh[i] = 0;
|
||||
pins[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EncoderSplitTestLeftEqRight, TestInitLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(pinIsInputHigh[4], false);
|
||||
EXPECT_EQ(pinIsInputHigh[5], false);
|
||||
EXPECT_EQ(pinIsInputHigh[6], false);
|
||||
EXPECT_EQ(pinIsInputHigh[7], false);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftEqRight, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], false);
|
||||
EXPECT_EQ(pinIsInputHigh[1], false);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(pinIsInputHigh[4], true);
|
||||
EXPECT_EQ(pinIsInputHigh[5], true);
|
||||
EXPECT_EQ(pinIsInputHigh[6], true);
|
||||
EXPECT_EQ(pinIsInputHigh[7], true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 1); // one update received
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSent) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(6, false);
|
||||
setAndRead(7, false);
|
||||
setAndRead(6, true);
|
||||
setAndRead(7, true);
|
||||
|
||||
uint8_t slave_state[32] = {0};
|
||||
encoder_state_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(slave_state[0], 0);
|
||||
EXPECT_EQ(slave_state[1], 0xFF);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftEqRight, TestMultipleEncodersRightReceived) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder CW
|
||||
encoder_update_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
|
||||
EXPECT_EQ(updates[0].index, 2);
|
||||
EXPECT_EQ(updates[0].clockwise, false);
|
||||
EXPECT_EQ(updates[1].index, 3);
|
||||
EXPECT_EQ(updates[1].clockwise, true);
|
||||
}
|
||||
139
quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
Normal file
139
quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/* Copyright 2021 Balz Guenat
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* 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 "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "encoder.h"
|
||||
#include "encoder/tests/mock_split.h"
|
||||
}
|
||||
|
||||
struct update {
|
||||
int8_t index;
|
||||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool isLeftHand;
|
||||
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
if (!isLeftHand) {
|
||||
// this method has no effect on slave half
|
||||
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
|
||||
return true;
|
||||
}
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setAndRead(pin_t pin, bool val) {
|
||||
setPin(pin, val);
|
||||
return encoder_read();
|
||||
}
|
||||
|
||||
class EncoderSplitTestLeftGreaterThanRight : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
updates_array_idx = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
pinIsInputHigh[i] = 0;
|
||||
pins[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EncoderSplitTestLeftGreaterThanRight, TestInitLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(pinIsInputHigh[4], true);
|
||||
EXPECT_EQ(pinIsInputHigh[5], true);
|
||||
EXPECT_EQ(pinIsInputHigh[6], false);
|
||||
EXPECT_EQ(pinIsInputHigh[7], false);
|
||||
EXPECT_EQ(pinIsInputHigh[8], false);
|
||||
EXPECT_EQ(pinIsInputHigh[9], false);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftGreaterThanRight, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], false);
|
||||
EXPECT_EQ(pinIsInputHigh[1], false);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(pinIsInputHigh[4], false);
|
||||
EXPECT_EQ(pinIsInputHigh[5], false);
|
||||
EXPECT_EQ(pinIsInputHigh[6], true);
|
||||
EXPECT_EQ(pinIsInputHigh[7], true);
|
||||
EXPECT_EQ(pinIsInputHigh[8], true);
|
||||
EXPECT_EQ(pinIsInputHigh[9], true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 1); // one update received
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSent) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(6, false);
|
||||
setAndRead(7, false);
|
||||
setAndRead(6, true);
|
||||
setAndRead(7, true);
|
||||
|
||||
uint8_t slave_state[32] = {0};
|
||||
encoder_state_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(slave_state[0], 0xFF);
|
||||
EXPECT_EQ(slave_state[1], 0);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftGreaterThanRight, TestMultipleEncodersRightReceived) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
|
||||
encoder_update_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
|
||||
EXPECT_EQ(updates[0].index, 3);
|
||||
EXPECT_EQ(updates[0].clockwise, false);
|
||||
EXPECT_EQ(updates[1].index, 4);
|
||||
EXPECT_EQ(updates[1].clockwise, true);
|
||||
}
|
||||
139
quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
Normal file
139
quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/* Copyright 2021 Balz Guenat
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* 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 "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "encoder.h"
|
||||
#include "encoder/tests/mock_split.h"
|
||||
}
|
||||
|
||||
struct update {
|
||||
int8_t index;
|
||||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool isLeftHand;
|
||||
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
if (!isLeftHand) {
|
||||
// this method has no effect on slave half
|
||||
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
|
||||
return true;
|
||||
}
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setAndRead(pin_t pin, bool val) {
|
||||
setPin(pin, val);
|
||||
return encoder_read();
|
||||
}
|
||||
|
||||
class EncoderSplitTestLeftLessThanRight : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
updates_array_idx = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
pinIsInputHigh[i] = 0;
|
||||
pins[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EncoderSplitTestLeftLessThanRight, TestInitLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(pinIsInputHigh[4], false);
|
||||
EXPECT_EQ(pinIsInputHigh[5], false);
|
||||
EXPECT_EQ(pinIsInputHigh[6], false);
|
||||
EXPECT_EQ(pinIsInputHigh[7], false);
|
||||
EXPECT_EQ(pinIsInputHigh[8], false);
|
||||
EXPECT_EQ(pinIsInputHigh[9], false);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftLessThanRight, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], false);
|
||||
EXPECT_EQ(pinIsInputHigh[1], false);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(pinIsInputHigh[4], true);
|
||||
EXPECT_EQ(pinIsInputHigh[5], true);
|
||||
EXPECT_EQ(pinIsInputHigh[6], true);
|
||||
EXPECT_EQ(pinIsInputHigh[7], true);
|
||||
EXPECT_EQ(pinIsInputHigh[8], true);
|
||||
EXPECT_EQ(pinIsInputHigh[9], true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 1); // one update received
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSent) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(6, false);
|
||||
setAndRead(7, false);
|
||||
setAndRead(6, true);
|
||||
setAndRead(7, true);
|
||||
|
||||
uint8_t slave_state[32] = {0};
|
||||
encoder_state_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(slave_state[0], 0);
|
||||
EXPECT_EQ(slave_state[1], 0xFF);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestLeftLessThanRight, TestMultipleEncodersRightReceived) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[32] = {1, 0, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
|
||||
encoder_update_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
|
||||
EXPECT_EQ(updates[0].index, 2);
|
||||
EXPECT_EQ(updates[0].clockwise, false);
|
||||
EXPECT_EQ(updates[1].index, 4);
|
||||
EXPECT_EQ(updates[1].clockwise, true);
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ struct update {
|
|||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t uidx = 0;
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool isLeftHand;
|
||||
|
|
@ -41,8 +41,8 @@ bool encoder_update_kb(uint8_t index, bool clockwise) {
|
|||
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
|
||||
return true;
|
||||
}
|
||||
updates[uidx % 32] = {index, clockwise};
|
||||
uidx++;
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +51,10 @@ bool setAndRead(pin_t pin, bool val) {
|
|||
return encoder_read();
|
||||
}
|
||||
|
||||
class EncoderTest : public ::testing::Test {
|
||||
class EncoderSplitTestNoLeft : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
uidx = 0;
|
||||
updates_array_idx = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
pinIsInputHigh[i] = 0;
|
||||
pins[i] = 0;
|
||||
|
|
@ -62,27 +62,27 @@ class EncoderTest : public ::testing::Test {
|
|||
}
|
||||
};
|
||||
|
||||
TEST_F(EncoderTest, TestInitLeft) {
|
||||
TEST_F(EncoderSplitTestNoLeft, TestInitLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], false);
|
||||
EXPECT_EQ(pinIsInputHigh[1], false);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(uidx, 0);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestOneClockwiseLeft) {
|
||||
TEST_F(EncoderSplitTestNoLeft, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
|
|
@ -91,12 +91,10 @@ TEST_F(EncoderTest, TestOneClockwiseLeft) {
|
|||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderTest, TestOneClockwiseRightSent) {
|
||||
TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSent) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
|
|
@ -105,39 +103,23 @@ TEST_F(EncoderTest, TestOneClockwiseRightSent) {
|
|||
setAndRead(2, true);
|
||||
setAndRead(3, true);
|
||||
|
||||
uint8_t slave_state[2] = {0};
|
||||
uint8_t slave_state[32] = {0};
|
||||
encoder_state_raw(slave_state);
|
||||
|
||||
EXPECT_EQ((int8_t)slave_state[0], -1);
|
||||
EXPECT_EQ(slave_state[0], 0);
|
||||
EXPECT_EQ(slave_state[1], 0xFF);
|
||||
}
|
||||
|
||||
/* this test will not work after the previous test.
|
||||
* this is due to encoder_value[1] already being set to -1 when simulating the right half.
|
||||
* When we now receive this update acting as the left half, there is no change.
|
||||
* This is hard to mock, as the static values inside encoder.c normally exist twice, once on each half,
|
||||
* but here, they only exist once.
|
||||
*/
|
||||
|
||||
// TEST_F(EncoderTest, TestOneClockwiseRightReceived) {
|
||||
// isLeftHand = true;
|
||||
// encoder_init();
|
||||
|
||||
// uint8_t slave_state[2] = {255, 0};
|
||||
// encoder_update_raw(slave_state);
|
||||
|
||||
// EXPECT_EQ(uidx, 1);
|
||||
// EXPECT_EQ(updates[0].index, 1);
|
||||
// EXPECT_EQ(updates[0].clockwise, true);
|
||||
// }
|
||||
|
||||
TEST_F(EncoderTest, TestOneCounterClockwiseRightReceived) {
|
||||
TEST_F(EncoderSplitTestNoLeft, TestMultipleEncodersRightReceived) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[2] = {0, 0};
|
||||
uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
|
||||
encoder_update_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(uidx, 1);
|
||||
EXPECT_EQ(updates[0].index, 1);
|
||||
EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, false);
|
||||
EXPECT_EQ(updates[1].index, 1);
|
||||
EXPECT_EQ(updates[1].clockwise, true);
|
||||
}
|
||||
118
quantum/encoder/tests/encoder_tests_split_no_right.cpp
Normal file
118
quantum/encoder/tests/encoder_tests_split_no_right.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* Copyright 2021 Balz Guenat
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* 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 "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "encoder.h"
|
||||
#include "encoder/tests/mock_split.h"
|
||||
}
|
||||
|
||||
struct update {
|
||||
int8_t index;
|
||||
bool clockwise;
|
||||
};
|
||||
|
||||
uint8_t updates_array_idx = 0;
|
||||
update updates[32];
|
||||
|
||||
bool isLeftHand;
|
||||
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
if (!isLeftHand) {
|
||||
// this method has no effect on slave half
|
||||
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
|
||||
return true;
|
||||
}
|
||||
updates[updates_array_idx % 32] = {index, clockwise};
|
||||
updates_array_idx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setAndRead(pin_t pin, bool val) {
|
||||
setPin(pin, val);
|
||||
return encoder_read();
|
||||
}
|
||||
|
||||
class EncoderSplitTestNoRight : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
updates_array_idx = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
pinIsInputHigh[i] = 0;
|
||||
pins[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EncoderSplitTestNoRight, TestInitLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], true);
|
||||
EXPECT_EQ(pinIsInputHigh[1], true);
|
||||
EXPECT_EQ(pinIsInputHigh[2], true);
|
||||
EXPECT_EQ(pinIsInputHigh[3], true);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestNoRight, TestInitRight) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
EXPECT_EQ(pinIsInputHigh[0], false);
|
||||
EXPECT_EQ(pinIsInputHigh[1], false);
|
||||
EXPECT_EQ(pinIsInputHigh[2], false);
|
||||
EXPECT_EQ(pinIsInputHigh[3], false);
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestNoRight, TestOneClockwiseLeft) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
|
||||
setAndRead(0, false);
|
||||
setAndRead(1, false);
|
||||
setAndRead(0, true);
|
||||
setAndRead(1, true);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 1); // one updates received
|
||||
EXPECT_EQ(updates[0].index, 0);
|
||||
EXPECT_EQ(updates[0].clockwise, true);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestNoRight, TestOneClockwiseRightSent) {
|
||||
isLeftHand = false;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[32] = {0xAA, 0xAA};
|
||||
encoder_state_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(slave_state[0], 0xAA);
|
||||
EXPECT_EQ(slave_state[1], 0xAA);
|
||||
}
|
||||
|
||||
TEST_F(EncoderSplitTestNoRight, TestMultipleEncodersRightReceived) {
|
||||
isLeftHand = true;
|
||||
encoder_init();
|
||||
|
||||
uint8_t slave_state[32] = {1, 0xFF}; // These values would trigger updates if there were encoders on the other side
|
||||
encoder_update_raw(slave_state);
|
||||
|
||||
EXPECT_EQ(updates_array_idx, 0); // no updates received -- no right-hand encoders
|
||||
}
|
||||
|
|
@ -19,12 +19,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1 }
|
||||
|
||||
typedef uint8_t pin_t;
|
||||
|
||||
extern bool pins[];
|
||||
|
|
|
|||
|
|
@ -20,20 +20,10 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#define SPLIT_KEYBOARD
|
||||
/* Here, "pins" from 0 to 31 are allowed. */
|
||||
#define ENCODERS_PAD_A \
|
||||
{ 0 }
|
||||
#define ENCODERS_PAD_B \
|
||||
{ 1 }
|
||||
#define ENCODERS_PAD_A_RIGHT \
|
||||
{ 2 }
|
||||
#define ENCODERS_PAD_B_RIGHT \
|
||||
{ 3 }
|
||||
|
||||
typedef uint8_t pin_t;
|
||||
extern bool isLeftHand;
|
||||
void encoder_state_raw(uint8_t* slave_state);
|
||||
void encoder_update_raw(uint8_t* slave_state);
|
||||
|
||||
void encoder_state_raw(uint8_t* slave_state);
|
||||
void encoder_update_raw(uint8_t* slave_state);
|
||||
|
||||
extern bool pins[];
|
||||
extern bool pinIsInputHigh[];
|
||||
|
|
|
|||
|
|
@ -1,13 +1,58 @@
|
|||
encoder_DEFS := -DENCODER_MOCK_SINGLE
|
||||
encoder_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SINGLE
|
||||
encoder_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock.h
|
||||
|
||||
encoder_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
||||
encoder_split_DEFS := -DENCODER_MOCK_SPLIT
|
||||
encoder_split_left_eq_right_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SPLIT
|
||||
encoder_split_left_eq_right_INC := $(QUANTUM_PATH)/split_common
|
||||
encoder_split_left_eq_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_left_eq_right.h
|
||||
|
||||
encoder_split_SRC := \
|
||||
encoder_split_left_eq_right_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split.cpp \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_eq_right.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
||||
encoder_split_left_gt_right_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SPLIT
|
||||
encoder_split_left_gt_right_INC := $(QUANTUM_PATH)/split_common
|
||||
encoder_split_left_gt_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_left_gt_right.h
|
||||
|
||||
encoder_split_left_gt_right_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_gt_right.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
||||
encoder_split_left_lt_right_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SPLIT
|
||||
encoder_split_left_lt_right_INC := $(QUANTUM_PATH)/split_common
|
||||
encoder_split_left_lt_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_left_lt_right.h
|
||||
|
||||
encoder_split_left_lt_right_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_lt_right.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
||||
encoder_split_no_left_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SPLIT
|
||||
encoder_split_no_left_INC := $(QUANTUM_PATH)/split_common
|
||||
encoder_split_no_left_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_no_left.h
|
||||
|
||||
encoder_split_no_left_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_left.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
||||
encoder_split_no_right_DEFS := -DENCODER_TESTS -DENCODER_ENABLE -DENCODER_MOCK_SPLIT
|
||||
encoder_split_no_right_INC := $(QUANTUM_PATH)/split_common
|
||||
encoder_split_no_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_no_right.h
|
||||
|
||||
encoder_split_no_right_SRC := \
|
||||
platforms/test/timer.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
|
||||
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_right.cpp \
|
||||
$(QUANTUM_PATH)/encoder.c
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
TEST_LIST += \
|
||||
encoder \
|
||||
encoder_split
|
||||
encoder_split_left_eq_right \
|
||||
encoder_split_left_gt_right \
|
||||
encoder_split_left_lt_right \
|
||||
encoder_split_no_left \
|
||||
encoder_split_no_right
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ void haptic_play(void) {
|
|||
DRV_pulse(play_eff);
|
||||
#endif
|
||||
#ifdef SOLENOID_ENABLE
|
||||
solenoid_fire();
|
||||
solenoid_fire_handler();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,38 @@
|
|||
#include "joystick.h"
|
||||
|
||||
joystick_t joystick_status = {.buttons = {0},
|
||||
.axes =
|
||||
{
|
||||
// clang-format off
|
||||
joystick_t joystick_status = {
|
||||
.buttons = {0},
|
||||
.axes = {
|
||||
#if JOYSTICK_AXES_COUNT > 0
|
||||
0
|
||||
0
|
||||
#endif
|
||||
},
|
||||
.status = 0};
|
||||
},
|
||||
.status = 0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// array defining the reading of analog values for each axis
|
||||
__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {};
|
||||
|
||||
// to be implemented in the hid protocol library
|
||||
void send_joystick_packet(joystick_t *joystick);
|
||||
|
||||
void joystick_flush(void) {
|
||||
if ((joystick_status.status & JS_UPDATED) > 0) {
|
||||
send_joystick_packet(&joystick_status);
|
||||
joystick_status.status &= ~JS_UPDATED;
|
||||
}
|
||||
}
|
||||
|
||||
void register_joystick_button(uint8_t button) {
|
||||
joystick_status.buttons[button / 8] |= 1 << (button % 8);
|
||||
joystick_status.status |= JS_UPDATED;
|
||||
joystick_flush();
|
||||
}
|
||||
|
||||
void unregister_joystick_button(uint8_t button) {
|
||||
joystick_status.buttons[button / 8] &= ~(1 << (button % 8));
|
||||
joystick_status.status |= JS_UPDATED;
|
||||
joystick_flush();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gpio.h"
|
||||
|
||||
#ifndef JOYSTICK_BUTTON_COUNT
|
||||
# define JOYSTICK_BUTTON_COUNT 8
|
||||
#elif JOYSTICK_BUTTON_COUNT > 32
|
||||
# error Joystick feature only supports up to 32 buttons
|
||||
#endif
|
||||
|
||||
#ifndef JOYSTICK_AXES_COUNT
|
||||
# define JOYSTICK_AXES_COUNT 4
|
||||
#elif JOYSTICK_AXES_COUNT > 6
|
||||
# error Joystick feature only supports up to 6 axes
|
||||
#endif
|
||||
|
||||
#if JOYSTICK_AXES_COUNT == 0 && JOYSTICK_BUTTON_COUNT == 0
|
||||
# error Joystick feature requires at least one axis or button
|
||||
#endif
|
||||
|
||||
#ifndef JOYSTICK_AXES_RESOLUTION
|
||||
|
|
@ -58,5 +65,7 @@ typedef struct {
|
|||
|
||||
extern joystick_t joystick_status;
|
||||
|
||||
// to be implemented in the hid protocol library
|
||||
void send_joystick_packet(joystick_t *joystick);
|
||||
void joystick_flush(void);
|
||||
|
||||
void register_joystick_button(uint8_t button);
|
||||
void unregister_joystick_button(uint8_t button);
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifdef BLUETOOTH_ENABLE
|
||||
# include "outputselect.h"
|
||||
#endif
|
||||
#ifdef CAPS_WORD_ENABLE
|
||||
# include "caps_word.h"
|
||||
#endif
|
||||
|
||||
static uint32_t last_input_modification_time = 0;
|
||||
uint32_t last_input_activity_time(void) {
|
||||
|
|
@ -155,7 +158,7 @@ void matrix_scan_perf_task(void) {
|
|||
matrix_scan_count++;
|
||||
|
||||
uint32_t timer_now = timer_read32();
|
||||
if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) {
|
||||
if (TIMER_DIFF_32(timer_now, matrix_timer) >= 1000) {
|
||||
# if defined(CONSOLE_ENABLE)
|
||||
dprintf("matrix scan frequency: %lu\n", matrix_scan_count);
|
||||
# endif
|
||||
|
|
@ -217,17 +220,6 @@ static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) {
|
|||
|
||||
#endif
|
||||
|
||||
void disable_jtag(void) {
|
||||
// To use PF4-7 (PC2-5 on ATmega32A), disable JTAG by writing JTD bit twice within four cycles.
|
||||
#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
|
||||
MCUCR |= _BV(JTD);
|
||||
MCUCR |= _BV(JTD);
|
||||
#elif defined(__AVR_ATmega32A__)
|
||||
MCUCSR |= _BV(JTD);
|
||||
MCUCSR |= _BV(JTD);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief matrix_setup
|
||||
*
|
||||
* FIXME: needs doc
|
||||
|
|
@ -269,9 +261,6 @@ __attribute__((weak)) void keyboard_post_init_kb(void) {
|
|||
* FIXME: needs doc
|
||||
*/
|
||||
void keyboard_setup(void) {
|
||||
#ifndef NO_JTAG_DISABLE
|
||||
disable_jtag();
|
||||
#endif
|
||||
print_set_sendchar(sendchar);
|
||||
#ifdef EEPROM_DRIVER
|
||||
eeprom_driver_init();
|
||||
|
|
@ -501,7 +490,7 @@ bool matrix_scan_task(void) {
|
|||
// we can get here with some keys processed now.
|
||||
if (!keys_processed)
|
||||
#endif
|
||||
action_exec(TICK);
|
||||
action_exec(TICK_EVENT);
|
||||
|
||||
MATRIX_LOOP_END:
|
||||
|
||||
|
|
@ -574,6 +563,14 @@ void quantum_task(void) {
|
|||
#ifdef AUTO_SHIFT_ENABLE
|
||||
autoshift_matrix_scan();
|
||||
#endif
|
||||
|
||||
#ifdef CAPS_WORD_ENABLE
|
||||
caps_word_task();
|
||||
#endif
|
||||
|
||||
#ifdef SECURE_ENABLE
|
||||
secure_task();
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief Keyboard task: Do keyboard routine jobs
|
||||
|
|
|
|||
|
|
@ -40,25 +40,47 @@ typedef struct {
|
|||
/* equivalent test of keypos_t */
|
||||
#define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col)
|
||||
|
||||
/* special keypos_t entries */
|
||||
#define KEYLOC_TICK 255
|
||||
#define KEYLOC_COMBO 254
|
||||
#define KEYLOC_ENCODER_CW 253
|
||||
#define KEYLOC_ENCODER_CCW 252
|
||||
|
||||
/* Rules for No Event:
|
||||
* 1) (time == 0) to handle (keyevent_t){} as empty event
|
||||
* 2) Matrix(255, 255) to make TICK event available
|
||||
*/
|
||||
static inline bool IS_NOEVENT(keyevent_t event) {
|
||||
return event.time == 0 || (event.key.row == 255 && event.key.col == 255);
|
||||
return event.time == 0 || (event.key.row == KEYLOC_TICK && event.key.col == KEYLOC_TICK);
|
||||
}
|
||||
static inline bool IS_KEYEVENT(keyevent_t event) {
|
||||
return event.key.row < MATRIX_ROWS && event.key.col < MATRIX_COLS;
|
||||
}
|
||||
static inline bool IS_COMBOEVENT(keyevent_t event) {
|
||||
return event.key.row == KEYLOC_COMBO;
|
||||
}
|
||||
static inline bool IS_ENCODEREVENT(keyevent_t event) {
|
||||
return event.key.row == KEYLOC_ENCODER_CW || event.key.row == KEYLOC_ENCODER_CCW;
|
||||
}
|
||||
static inline bool IS_PRESSED(keyevent_t event) {
|
||||
return (!IS_NOEVENT(event) && event.pressed);
|
||||
return !IS_NOEVENT(event) && event.pressed;
|
||||
}
|
||||
static inline bool IS_RELEASED(keyevent_t event) {
|
||||
return (!IS_NOEVENT(event) && !event.pressed);
|
||||
return !IS_NOEVENT(event) && !event.pressed;
|
||||
}
|
||||
|
||||
/* Common keyevent object factory */
|
||||
#define MAKE_KEYPOS(row_num, col_num) ((keypos_t){.row = (row_num), .col = (col_num)})
|
||||
#define MAKE_KEYEVENT(row_num, col_num, press) ((keyevent_t){.key = MAKE_KEYPOS((row_num), (col_num)), .pressed = (press), .time = (timer_read() | 1)})
|
||||
|
||||
/* Tick event */
|
||||
#define TICK \
|
||||
(keyevent_t) { \
|
||||
.key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) \
|
||||
}
|
||||
#define TICK_EVENT MAKE_KEYEVENT(KEYLOC_TICK, KEYLOC_TICK, false)
|
||||
|
||||
#ifdef ENCODER_MAP_ENABLE
|
||||
/* Encoder events */
|
||||
# define ENCODER_CW_EVENT(enc_id, press) MAKE_KEYEVENT(KEYLOC_ENCODER_CW, (enc_id), (press))
|
||||
# define ENCODER_CCW_EVENT(enc_id, press) MAKE_KEYEVENT(KEYLOC_ENCODER_CCW, (enc_id), (press))
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
|
||||
/* it runs once at early stage of startup before keyboard_init. */
|
||||
void keyboard_setup(void);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ typedef union {
|
|||
bool nkro : 1;
|
||||
bool swap_lctl_lgui : 1;
|
||||
bool swap_rctl_rgui : 1;
|
||||
bool oneshot_disable : 1;
|
||||
bool oneshot_enable : 1;
|
||||
};
|
||||
} keymap_config_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// #include "print.h"
|
||||
#include "debug.h"
|
||||
#include "keycode_config.h"
|
||||
#include "gpio.h" // for pin_t
|
||||
|
||||
// ChibiOS uses RESET in its FlagStatus enumeration
|
||||
// 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/>.
|
|||
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
|
||||
|
||||
extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
|
||||
|
||||
#ifdef ENCODER_MAP_ENABLE
|
||||
// Ensure we have a forward declaration for the encoder map
|
||||
# include "encoder.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -148,6 +148,15 @@ action_t action_for_keycode(uint16_t keycode) {
|
|||
|
||||
// translates key to keycode
|
||||
__attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
|
||||
// Read entire word (16bits)
|
||||
return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
|
||||
if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) {
|
||||
return pgm_read_word(&keymaps[layer][key.row][key.col]);
|
||||
}
|
||||
#ifdef ENCODER_MAP_ENABLE
|
||||
else if (key.row == KEYLOC_ENCODER_CW && key.col < NUM_ENCODERS) {
|
||||
return pgm_read_word(&encoder_map[layer][key.col][0]);
|
||||
} else if (key.row == KEYLOC_ENCODER_CCW && key.col < NUM_ENCODERS) {
|
||||
return pgm_read_word(&encoder_map[layer][key.col][1]);
|
||||
}
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
return KC_NO;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@
|
|||
#define BR_SCLN KC_SLSH // ;
|
||||
#define BR_SLSH KC_INT1 // /
|
||||
// Numpad
|
||||
#define BR_PDOT KC_PCMM // .
|
||||
#define BR_PCMM KC_PDOT // ,
|
||||
#define BR_PDOT KC_PCMM // .
|
||||
#define BR_PCMM KC_PDOT // ,
|
||||
|
||||
/* Shifted symbols
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
|
|
@ -140,12 +140,12 @@
|
|||
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
|
||||
*/
|
||||
// Row 2
|
||||
#define IT_EURO ALGR(IT_E) // €
|
||||
#define IT_LBRC ALGR(IT_EGRV) // [
|
||||
#define IT_RBRC ALGR(IT_PLUS) // ]
|
||||
#define IT_EURO ALGR(IT_E) // €
|
||||
#define IT_LBRC ALGR(IT_EGRV) // [
|
||||
#define IT_RBRC ALGR(IT_PLUS) // ]
|
||||
// Row 3
|
||||
#define IT_AT ALGR(IT_OGRV) // @
|
||||
#define IT_HASH ALGR(IT_AGRV) // #
|
||||
#define IT_AT ALGR(IT_OGRV) // @
|
||||
#define IT_HASH ALGR(IT_AGRV) // #
|
||||
|
||||
/* Shift+AltGr symbols
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
|
|
|
|||
134
quantum/keymap_extras/keymap_ukrainian.h
Normal file
134
quantum/keymap_extras/keymap_ukrainian.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/* Copyright 2022
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keymap.h"
|
||||
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
* │ ' │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ │
|
||||
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
|
||||
* │ │ Й │ Ц │ У │ К │ Е │ Н │ Г │ Ш │ Щ │ З │ Х │ Ї │ \ │
|
||||
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
|
||||
* │ │ Ф │ І │ В │ А │ П │ Р │ О │ Л │ Д │ Ж │ Є │ │
|
||||
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
|
||||
* │ │ Я │ Ч │ С │ М │ И │ Т │ Ь │ Б │ Ю │ . │ │
|
||||
* ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
|
||||
* │ │ │ │ │ │ │ │ │
|
||||
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
|
||||
*/
|
||||
// Row 1
|
||||
#define UA_QUOT KC_GRV // '
|
||||
#define UA_1 KC_1 // 1
|
||||
#define UA_2 KC_2 // 2
|
||||
#define UA_3 KC_3 // 3
|
||||
#define UA_4 KC_4 // 4
|
||||
#define UA_5 KC_5 // 5
|
||||
#define UA_6 KC_6 // 6
|
||||
#define UA_7 KC_7 // 7
|
||||
#define UA_8 KC_8 // 8
|
||||
#define UA_9 KC_9 // 9
|
||||
#define UA_0 KC_0 // 0
|
||||
#define UA_MINS KC_MINS // -
|
||||
#define UA_EQL KC_EQL // =
|
||||
// Row 2
|
||||
#define UA_YOT KC_Q // Й
|
||||
#define UA_TSE KC_W // Ц
|
||||
#define UA_U KC_E // У
|
||||
#define UA_KA KC_R // К
|
||||
#define UA_E KC_T // Е
|
||||
#define UA_EN KC_Y // Н
|
||||
#define UA_HE KC_U // Г
|
||||
#define UA_SHA KC_I // Ш
|
||||
#define UA_SHCH KC_O // Щ
|
||||
#define UA_ZE KC_P // З
|
||||
#define UA_KHA KC_LBRC // Х
|
||||
#define UA_YI KC_RBRC // Ї
|
||||
#define UA_BSLS KC_BSLS // (backslash)
|
||||
// Row 3
|
||||
#define UA_EF KC_A // Ф
|
||||
#define UA_I KC_S // І
|
||||
#define UA_VE KC_D // В
|
||||
#define UA_A KC_F // А
|
||||
#define UA_PE KC_G // П
|
||||
#define UA_ER KC_H // Р
|
||||
#define UA_O KC_J // О
|
||||
#define UA_EL KC_K // Л
|
||||
#define UA_DE KC_L // Д
|
||||
#define UA_ZHE KC_SCLN // Ж
|
||||
#define UA_YE KC_QUOT // Є
|
||||
// Row 4
|
||||
#define UA_YA KC_Z // Я
|
||||
#define UA_CHE KC_X // Ч
|
||||
#define UA_ES KC_C // С
|
||||
#define UA_EM KC_V // М
|
||||
#define UA_Y KC_B // И
|
||||
#define UA_TE KC_N // Т
|
||||
#define UA_SOFT KC_M // Ь
|
||||
#define UA_BE KC_COMM // Б
|
||||
#define UA_YU KC_DOT // Ю
|
||||
#define UA_DOT KC_SLSH // .
|
||||
|
||||
/* Shifted symbols
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
* │ ₴ │ ! │ " │ № │ ; │ % │ : │ ? │ * │ ( │ ) │ _ │ + │ │
|
||||
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
|
||||
* │ │ │ │ │ │ │ │ │ │ │ │ │ │ / │
|
||||
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
|
||||
* │ │ │ │ │ │ │ │ │ │ │ │ │ │
|
||||
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
|
||||
* │ │ │ │ │ │ │ │ │ │ │ , │ │
|
||||
* ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
|
||||
* │ │ │ │ │ │ │ │ │
|
||||
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
|
||||
*/
|
||||
// Row 1
|
||||
#define UA_HRYV S(UA_QUOT) // ₴
|
||||
#define UA_EXLM S(UA_1) // !
|
||||
#define UA_DQUO S(UA_2) // "
|
||||
#define UA_NUM S(UA_3) // №
|
||||
#define UA_SCLN S(UA_4) // ;
|
||||
#define UA_PERC S(UA_5) // %
|
||||
#define UA_COLN S(UA_6) // :
|
||||
#define UA_QUES S(UA_7) // ?
|
||||
#define UA_ASTR S(UA_8) // *
|
||||
#define UA_LPRN S(UA_9) // (
|
||||
#define UA_RPRN S(UA_0) // )
|
||||
#define UA_UNDS S(UA_MINS) // _
|
||||
#define UA_PLUS S(UA_EQL) // +
|
||||
// Row 2
|
||||
#define UA_SLSH S(UA_BSLS) // /
|
||||
// Row 4
|
||||
#define UA_COMM S(UA_DOT) // ,
|
||||
|
||||
/* AltGr symbols
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
* │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
|
||||
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
|
||||
* │ │ │ │ │ │ │ │ ґ │ │ │ │ │ │ │
|
||||
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
|
||||
* │ │ │ │ │ │ │ │ │ │ │ │ │ │
|
||||
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
|
||||
* │ │ │ │ │ │ │ │ │ │ │ │ │
|
||||
* ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
|
||||
* │ │ │ │ │ │ │ │ │
|
||||
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
|
||||
*/
|
||||
// Row 2
|
||||
#define UA_GE ALGR(UA_HE) // ґ
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_br_abnt2.h"
|
||||
#include "keymap_brazilian_abnt2.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -43,6 +43,26 @@ const uint8_t ascii_to_shift_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 1, 0),
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,25 @@ const uint8_t ascii_to_shift_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 0, 1, 0, 0, 0),
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_dvp.h"
|
||||
#include "keymap_dvorak_programmer.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_french_osx.h"
|
||||
#include "keymap_french_mac_iso.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_german_osx.h"
|
||||
#include "keymap_german_mac_iso.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_italian_osx_ansi.h"
|
||||
#include "keymap_italian_mac_ansi.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_italian_osx_iso.h"
|
||||
#include "keymap_italian_mac_iso.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_jp.h"
|
||||
#include "keymap_japanese.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -19,9 +19,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "keymap_latvian.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 1, 0, 0, 0, 0, 1),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_portuguese_osx_iso.h"
|
||||
#include "keymap_portuguese_mac_iso.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_german_ch.h"
|
||||
#include "keymap_swiss_de.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_fr_ch.h"
|
||||
#include "keymap_swiss_fr.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
|
|||
KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_dead_lut[16] PROGMEM = {
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
|
||||
KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
|
||||
};
|
||||
|
||||
const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
|
||||
// NUL SOH STX ETX EOT ENQ ACK BEL
|
||||
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Sendstring lookup tables for UK layouts
|
||||
// Sendstring lookup tables for US International layouts
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@ void protocol_task(void) {
|
|||
protocol_post_task();
|
||||
}
|
||||
|
||||
#ifdef DEFERRED_EXEC_ENABLE
|
||||
void deferred_exec_task(void);
|
||||
#endif // DEFERRED_EXEC_ENABLE
|
||||
|
||||
/** \brief Main
|
||||
*
|
||||
* FIXME: Needs doc
|
||||
|
|
@ -63,8 +59,15 @@ int main(void) {
|
|||
while (true) {
|
||||
protocol_task();
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ENABLE
|
||||
// Run Quantum Painter animations
|
||||
void qp_internal_animation_tick(void);
|
||||
qp_internal_animation_tick();
|
||||
#endif
|
||||
|
||||
#ifdef DEFERRED_EXEC_ENABLE
|
||||
// Run deferred executions
|
||||
void deferred_exec_task(void);
|
||||
deferred_exec_task();
|
||||
#endif // DEFERRED_EXEC_ENABLE
|
||||
|
||||
|
|
|
|||
|
|
@ -72,15 +72,12 @@ inline matrix_row_t matrix_get_row(uint8_t row) {
|
|||
#if (MATRIX_COLS <= 8)
|
||||
# define print_matrix_header() print("\nr/c 01234567\n")
|
||||
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
|
||||
# define matrix_bitpop(row) bitpop(matrix_get_row(row))
|
||||
#elif (MATRIX_COLS <= 16)
|
||||
# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
|
||||
# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
|
||||
# define matrix_bitpop(row) bitpop16(matrix_get_row(row))
|
||||
#elif (MATRIX_COLS <= 32)
|
||||
# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
|
||||
# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
|
||||
# define matrix_bitpop(row) bitpop32(matrix_get_row(row))
|
||||
#endif
|
||||
|
||||
void matrix_print(void) {
|
||||
|
|
@ -94,14 +91,6 @@ void matrix_print(void) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t matrix_key_count(void) {
|
||||
uint8_t count = 0;
|
||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||
count += matrix_bitpop(i);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef SPLIT_KEYBOARD
|
||||
bool matrix_post_scan(void) {
|
||||
bool changed = false;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "keycode.h"
|
||||
#include "host.h"
|
||||
#include "timer.h"
|
||||
|
|
@ -210,7 +211,7 @@ static uint8_t wheel_unit(void) {
|
|||
|
||||
void mousekey_task(void) {
|
||||
// report cursor and scroll movement independently
|
||||
report_mouse_t const tmpmr = mouse_report;
|
||||
report_mouse_t tmpmr = mouse_report;
|
||||
|
||||
mouse_report.x = 0;
|
||||
mouse_report.y = 0;
|
||||
|
|
@ -252,8 +253,10 @@ void mousekey_task(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
|
||||
mouse_report = tmpmr;
|
||||
if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) {
|
||||
mousekey_send();
|
||||
}
|
||||
memcpy(&mouse_report, &tmpmr, sizeof(tmpmr));
|
||||
}
|
||||
|
||||
void mousekey_on(uint8_t code) {
|
||||
|
|
@ -357,11 +360,11 @@ uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0
|
|||
|
||||
void mousekey_task(void) {
|
||||
// report cursor and scroll movement independently
|
||||
report_mouse_t const tmpmr = mouse_report;
|
||||
mouse_report.x = 0;
|
||||
mouse_report.y = 0;
|
||||
mouse_report.v = 0;
|
||||
mouse_report.h = 0;
|
||||
report_mouse_t tmpmr = mouse_report;
|
||||
mouse_report.x = 0;
|
||||
mouse_report.y = 0;
|
||||
mouse_report.v = 0;
|
||||
mouse_report.h = 0;
|
||||
|
||||
if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) {
|
||||
mouse_report.x = tmpmr.x;
|
||||
|
|
@ -372,8 +375,10 @@ void mousekey_task(void) {
|
|||
mouse_report.h = tmpmr.h;
|
||||
}
|
||||
|
||||
if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
|
||||
mouse_report = tmpmr;
|
||||
if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) {
|
||||
mousekey_send();
|
||||
}
|
||||
memcpy(&mouse_report, &tmpmr, sizeof(tmpmr));
|
||||
}
|
||||
|
||||
void adjust_speed(void) {
|
||||
|
|
@ -523,3 +528,7 @@ static void mousekey_debug(void) {
|
|||
report_mouse_t mousekey_get_report(void) {
|
||||
return mouse_report;
|
||||
}
|
||||
|
||||
bool should_mousekey_report_send(report_mouse_t *mouse_report) {
|
||||
return mouse_report->x || mouse_report->y || mouse_report->v || mouse_report->h;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ void mousekey_off(uint8_t code);
|
|||
void mousekey_clear(void);
|
||||
void mousekey_send(void);
|
||||
report_mouse_t mousekey_get_report(void);
|
||||
bool should_mousekey_report_send(report_mouse_t *mouse_report);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
137
quantum/painter/qff.c
Normal file
137
quantum/painter/qff.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Quantum Font File "QFF" File Format.
|
||||
// See https://docs.qmk.fm/#/quantum_painter_qff for more information.
|
||||
|
||||
#include "qff.h"
|
||||
#include "qp_draw.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QFF API
|
||||
|
||||
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, painter_compression_t *compression_scheme, uint32_t *total_bytes) {
|
||||
// Seek to the start
|
||||
qp_stream_setpos(stream, 0);
|
||||
|
||||
// Read and validate the font descriptor
|
||||
qff_font_descriptor_v1_t font_descriptor;
|
||||
if (qp_stream_read(&font_descriptor, sizeof(qff_font_descriptor_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read font_descriptor, expected length was not %d\n", (int)sizeof(qff_font_descriptor_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&font_descriptor.header, QFF_FONT_DESCRIPTOR_TYPEID, (sizeof(qff_font_descriptor_v1_t) - sizeof(qgf_block_header_v1_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the magic and version are correct
|
||||
if (font_descriptor.magic != QFF_MAGIC || font_descriptor.qff_version != 0x01) {
|
||||
qp_dprintf("Failed to validate font_descriptor, expected magic 0x%06X was 0x%06X, expected version = 0x%02X was 0x%02X\n", (int)QFF_MAGIC, (int)font_descriptor.magic, (int)0x01, (int)font_descriptor.qff_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the file length is valid
|
||||
if (font_descriptor.neg_total_file_size != ~font_descriptor.total_file_size) {
|
||||
qp_dprintf("Failed to validate font_descriptor, expected negated length 0x%08X was 0x%08X\n", (int)(~font_descriptor.total_file_size), (int)font_descriptor.neg_total_file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy out the required info
|
||||
if (line_height) {
|
||||
*line_height = font_descriptor.line_height;
|
||||
}
|
||||
if (has_ascii_table) {
|
||||
*has_ascii_table = font_descriptor.has_ascii_table;
|
||||
}
|
||||
if (num_unicode_glyphs) {
|
||||
*num_unicode_glyphs = font_descriptor.num_unicode_glyphs;
|
||||
}
|
||||
if (bpp || has_palette) {
|
||||
if (!qgf_parse_format(font_descriptor.format, bpp, has_palette)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (compression_scheme) {
|
||||
*compression_scheme = font_descriptor.compression_scheme;
|
||||
}
|
||||
if (total_bytes) {
|
||||
*total_bytes = font_descriptor.total_file_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qff_validate_ascii_descriptor(qp_stream_t *stream) {
|
||||
// Read the raw descriptor
|
||||
qff_ascii_glyph_table_v1_t ascii_descriptor;
|
||||
if (qp_stream_read(&ascii_descriptor, sizeof(qff_ascii_glyph_table_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read ascii_descriptor, expected length was not %d\n", (int)sizeof(qff_ascii_glyph_table_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&ascii_descriptor.header, QFF_ASCII_GLYPH_DESCRIPTOR_TYPEID, (sizeof(qff_ascii_glyph_table_v1_t) - sizeof(qgf_block_header_v1_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qff_validate_unicode_descriptor(qp_stream_t *stream, uint16_t num_unicode_glyphs) {
|
||||
// Read the raw descriptor
|
||||
qff_unicode_glyph_table_v1_t unicode_descriptor;
|
||||
if (qp_stream_read(&unicode_descriptor, sizeof(qff_unicode_glyph_table_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read unicode_descriptor, expected length was not %d\n", (int)sizeof(qff_unicode_glyph_table_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&unicode_descriptor.header, QFF_UNICODE_GLYPH_DESCRIPTOR_TYPEID, num_unicode_glyphs * 6)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the necessary amount of data to get to the next block
|
||||
qp_stream_seek(stream, num_unicode_glyphs * sizeof(qff_unicode_glyph_v1_t), SEEK_CUR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qff_validate_stream(qp_stream_t *stream) {
|
||||
bool has_ascii_table;
|
||||
uint16_t num_unicode_glyphs;
|
||||
|
||||
if (!qff_read_font_descriptor(stream, NULL, &has_ascii_table, &num_unicode_glyphs, NULL, NULL, NULL, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (has_ascii_table) {
|
||||
if (!qff_validate_ascii_descriptor(stream)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_unicode_glyphs > 0) {
|
||||
if (!qff_validate_unicode_descriptor(stream, num_unicode_glyphs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t qff_get_total_size(qp_stream_t *stream) {
|
||||
// Get the original location
|
||||
uint32_t oldpos = qp_stream_tell(stream);
|
||||
|
||||
// Read the font descriptor, grabbing the size
|
||||
uint32_t total_size;
|
||||
if (!qff_read_font_descriptor(stream, NULL, NULL, NULL, NULL, NULL, NULL, &total_size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore the original location
|
||||
qp_stream_setpos(stream, oldpos);
|
||||
return total_size;
|
||||
}
|
||||
88
quantum/painter/qff.h
Normal file
88
quantum/painter/qff.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
// Quantum Font File "QFF" File Format.
|
||||
// See https://docs.qmk.fm/#/quantum_painter_qff for more information.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "qp_stream.h"
|
||||
#include "qp_internal.h"
|
||||
#include "qgf.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QFF structures
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Font descriptor
|
||||
|
||||
#define QFF_FONT_DESCRIPTOR_TYPEID 0x00
|
||||
|
||||
typedef struct __attribute__((packed)) qff_font_descriptor_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x00, .neg_type_id = (~0x00), .length = 20 }
|
||||
uint32_t magic : 24; // constant, equal to 0x464651 ("QFF")
|
||||
uint8_t qff_version; // constant, equal to 0x01
|
||||
uint32_t total_file_size; // total size of the entire file, starting at offset zero
|
||||
uint32_t neg_total_file_size; // negated value of total_file_size, used for detecting parsing errors
|
||||
uint8_t line_height; // glyph height in pixels
|
||||
bool has_ascii_table; // whether the font has an ascii table of glyphs (0x20...0x7E)
|
||||
uint16_t num_unicode_glyphs; // the number of glyphs in the unicode table -- no table specified if zero
|
||||
qp_image_format_t format : 8; // Frame format, see qp.h.
|
||||
uint8_t flags; // frame flags, see below.
|
||||
uint8_t compression_scheme; // compression scheme, see below.
|
||||
uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented)
|
||||
} qff_font_descriptor_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF");
|
||||
|
||||
#define QFF_MAGIC 0x464651
|
||||
|
||||
/////////////////////////////////////////
|
||||
// ASCII glyph table descriptor
|
||||
|
||||
#define QFF_ASCII_GLYPH_DESCRIPTOR_TYPEID 0x01
|
||||
|
||||
#define QFF_GLYPH_WIDTH_BITS 6
|
||||
#define QFF_GLYPH_WIDTH_MASK ((1 << QFF_GLYPH_WIDTH_BITS) - 1)
|
||||
#define QFF_GLYPH_OFFSET_BITS 18
|
||||
#define QFF_GLYPH_OFFSET_MASK (((1 << QFF_GLYPH_OFFSET_BITS) - 1) << QFF_GLYPH_WIDTH_BITS)
|
||||
|
||||
typedef struct __attribute__((packed)) qff_ascii_glyph_v1_t {
|
||||
uint32_t value : 24; // Uses QFF_GLYPH_*_(BITS|MASK) as bitfield ordering is compiler-defined
|
||||
} qff_ascii_glyph_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qff_ascii_glyph_v1_t) == 3, "qff_ascii_glyph_v1_t must be 3 bytes in v1 of QFF");
|
||||
|
||||
typedef struct __attribute__((packed)) qff_ascii_glyph_table_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x01, .neg_type_id = (~0x01), .length = 285 }
|
||||
qff_ascii_glyph_v1_t glyph[95]; // 95 glyphs, 0x20..0x7E
|
||||
} qff_ascii_glyph_table_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qff_ascii_glyph_table_v1_t) == (sizeof(qgf_block_header_v1_t) + (95 * sizeof(qff_ascii_glyph_v1_t))), "qff_ascii_glyph_table_v1_t must be 290 bytes in v1 of QFF");
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Unicode glyph table descriptor
|
||||
|
||||
#define QFF_UNICODE_GLYPH_DESCRIPTOR_TYPEID 0x02
|
||||
|
||||
typedef struct __attribute__((packed)) qff_unicode_glyph_v1_t {
|
||||
uint32_t code_point : 24;
|
||||
uint32_t value : 24; // Uses QFF_GLYPH_*_(BITS|MASK) as bitfield ordering is compiler-defined
|
||||
} qff_unicode_glyph_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qff_unicode_glyph_v1_t) == 6, "qff_unicode_glyph_v1_t must be 6 bytes in v1 of QFF");
|
||||
|
||||
typedef struct __attribute__((packed)) qff_unicode_glyph_table_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x02, .neg_type_id = (~0x02), .length = (N * 6) }
|
||||
qff_unicode_glyph_v1_t glyph[0]; // Extent of '0' signifies that this struct is immediately followed by the glyph data
|
||||
} qff_unicode_glyph_table_v1_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QFF API
|
||||
|
||||
bool qff_validate_stream(qp_stream_t *stream);
|
||||
uint32_t qff_get_total_size(qp_stream_t *stream);
|
||||
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, painter_compression_t *compression_scheme, uint32_t *total_bytes);
|
||||
292
quantum/painter/qgf.c
Normal file
292
quantum/painter/qgf.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Quantum Graphics File "QGF" File Format.
|
||||
// See https://docs.qmk.fm/#/quantum_painter_qgf for more information.
|
||||
|
||||
#include "qgf.h"
|
||||
#include "qp_draw.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QGF API
|
||||
|
||||
bool qgf_validate_block_header(qgf_block_header_v1_t *desc, uint8_t expected_typeid, int32_t expected_length) {
|
||||
if (desc->type_id != expected_typeid || desc->neg_type_id != ((~expected_typeid) & 0xFF)) {
|
||||
qp_dprintf("Failed to validate header, expected typeid 0x%02X, was 0x%02X, expected negated typeid 0x%02X, was 0x%02X\n", (int)expected_typeid, (int)desc->type_id, (int)((~desc->type_id) & 0xFF), (int)desc->neg_type_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_length >= 0 && desc->length != expected_length) {
|
||||
qp_dprintf("Failed to validate header (typeid 0x%02X), expected length %d, was %d\n", (int)desc->type_id, (int)expected_length, (int)desc->length);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette) {
|
||||
// clang-format off
|
||||
static const struct QP_PACKED {
|
||||
uint8_t bpp;
|
||||
bool has_palette;
|
||||
} formats[] = {
|
||||
[GRAYSCALE_1BPP] = {.bpp = 1, .has_palette = false},
|
||||
[GRAYSCALE_2BPP] = {.bpp = 2, .has_palette = false},
|
||||
[GRAYSCALE_4BPP] = {.bpp = 4, .has_palette = false},
|
||||
[GRAYSCALE_8BPP] = {.bpp = 8, .has_palette = false},
|
||||
[PALETTE_1BPP] = {.bpp = 1, .has_palette = true},
|
||||
[PALETTE_2BPP] = {.bpp = 2, .has_palette = true},
|
||||
[PALETTE_4BPP] = {.bpp = 4, .has_palette = true},
|
||||
[PALETTE_8BPP] = {.bpp = 8, .has_palette = true},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Copy out the required info
|
||||
if (format > PALETTE_8BPP) {
|
||||
qp_dprintf("Failed to parse frame_descriptor, invalid format 0x%02X\n", (int)format);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy out the required info
|
||||
if (bpp) {
|
||||
*bpp = formats[format].bpp;
|
||||
}
|
||||
if (has_palette) {
|
||||
*has_palette = formats[format].has_palette;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay) {
|
||||
// Decode the format
|
||||
qgf_parse_format(frame_descriptor->format, bpp, has_palette);
|
||||
|
||||
// Copy out the required info
|
||||
if (is_delta) {
|
||||
*is_delta = (frame_descriptor->flags & QGF_FRAME_FLAG_DELTA) == QGF_FRAME_FLAG_DELTA;
|
||||
}
|
||||
if (compression_scheme) {
|
||||
*compression_scheme = frame_descriptor->compression_scheme;
|
||||
}
|
||||
if (delay) {
|
||||
*delay = frame_descriptor->delay;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_read_graphics_descriptor(qp_stream_t *stream, uint16_t *image_width, uint16_t *image_height, uint16_t *frame_count, uint32_t *total_bytes) {
|
||||
// Seek to the start
|
||||
qp_stream_setpos(stream, 0);
|
||||
|
||||
// Read and validate the graphics descriptor
|
||||
qgf_graphics_descriptor_v1_t graphics_descriptor;
|
||||
if (qp_stream_read(&graphics_descriptor, sizeof(qgf_graphics_descriptor_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read graphics_descriptor, expected length was not %d\n", (int)sizeof(qgf_graphics_descriptor_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&graphics_descriptor.header, QGF_GRAPHICS_DESCRIPTOR_TYPEID, (sizeof(qgf_graphics_descriptor_v1_t) - sizeof(qgf_block_header_v1_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the magic and version are correct
|
||||
if (graphics_descriptor.magic != QGF_MAGIC || graphics_descriptor.qgf_version != 0x01) {
|
||||
qp_dprintf("Failed to validate graphics_descriptor, expected magic 0x%06X was 0x%06X, expected version = 0x%02X was 0x%02X\n", (int)QGF_MAGIC, (int)graphics_descriptor.magic, (int)0x01, (int)graphics_descriptor.qgf_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the file length is valid
|
||||
if (graphics_descriptor.neg_total_file_size != ~graphics_descriptor.total_file_size) {
|
||||
qp_dprintf("Failed to validate graphics_descriptor, expected negated length 0x%08X was 0x%08X\n", (int)(~graphics_descriptor.total_file_size), (int)graphics_descriptor.neg_total_file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy out the required info
|
||||
if (image_width) {
|
||||
*image_width = graphics_descriptor.image_width;
|
||||
}
|
||||
if (image_height) {
|
||||
*image_height = graphics_descriptor.image_height;
|
||||
}
|
||||
if (frame_count) {
|
||||
*frame_count = graphics_descriptor.frame_count;
|
||||
}
|
||||
if (total_bytes) {
|
||||
*total_bytes = graphics_descriptor.total_file_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qgf_read_frame_offset(qp_stream_t *stream, uint16_t frame_number, uint32_t *frame_offset) {
|
||||
uint16_t frame_count;
|
||||
if (!qgf_read_graphics_descriptor(stream, NULL, NULL, &frame_count, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the frame offsets descriptor
|
||||
qgf_frame_offsets_v1_t frame_offsets;
|
||||
if (qp_stream_read(&frame_offsets, sizeof(qgf_frame_offsets_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read frame_offsets, expected length was not %d\n", (int)sizeof(qgf_frame_offsets_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&frame_offsets.header, QGF_FRAME_OFFSET_DESCRIPTOR_TYPEID, (frame_count * sizeof(uint32_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frame_number >= frame_count) {
|
||||
qp_dprintf("Invalid frame number, was %d but only %d frames in image\n", (int)frame_number, (int)frame_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the necessary amount of data to get to the requested frame offset
|
||||
qp_stream_seek(stream, frame_number * sizeof(uint32_t), SEEK_CUR);
|
||||
|
||||
// Read the frame offset
|
||||
uint32_t offset = 0;
|
||||
if (qp_stream_read(&offset, sizeof(uint32_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read frame offset, expected length was not %d\n", (int)sizeof(uint32_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy out the required info
|
||||
if (frame_offset) {
|
||||
*frame_offset = offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qgf_seek_to_frame_descriptor(qp_stream_t *stream, uint16_t frame_number) {
|
||||
// Read the offset
|
||||
uint32_t offset = 0;
|
||||
qgf_read_frame_offset(stream, frame_number, &offset);
|
||||
|
||||
// Move to the offset
|
||||
qp_stream_setpos(stream, offset);
|
||||
}
|
||||
|
||||
bool qgf_validate_frame_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t *bpp, bool *has_palette, bool *is_delta) {
|
||||
// Seek to the correct location
|
||||
qgf_seek_to_frame_descriptor(stream, frame_number);
|
||||
|
||||
// Read the raw descriptor
|
||||
qgf_frame_v1_t frame_descriptor;
|
||||
if (qp_stream_read(&frame_descriptor, sizeof(qgf_frame_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read frame_descriptor, expected length was not %d\n", (int)sizeof(qgf_frame_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&frame_descriptor.header, QGF_FRAME_DESCRIPTOR_TYPEID, (sizeof(qgf_frame_v1_t) - sizeof(qgf_block_header_v1_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return qgf_parse_frame_descriptor(&frame_descriptor, bpp, has_palette, is_delta, NULL, NULL);
|
||||
}
|
||||
|
||||
bool qgf_validate_palette_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t bpp) {
|
||||
// Read the palette descriptor
|
||||
qgf_palette_v1_t palette_descriptor;
|
||||
if (qp_stream_read(&palette_descriptor, sizeof(qgf_palette_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read palette_descriptor, expected length was not %d\n", (int)sizeof(qgf_palette_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
uint32_t expected_length = (1 << bpp) * 3 * sizeof(uint8_t);
|
||||
if (!qgf_validate_block_header(&palette_descriptor.header, QGF_FRAME_PALETTE_DESCRIPTOR_TYPEID, expected_length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move forward in the stream to the next block
|
||||
qp_stream_seek(stream, expected_length, SEEK_CUR);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_validate_delta_descriptor(qp_stream_t *stream, uint16_t frame_number) {
|
||||
// Read the delta descriptor
|
||||
qgf_delta_v1_t delta_descriptor;
|
||||
if (qp_stream_read(&delta_descriptor, sizeof(qgf_delta_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read delta_descriptor, expected length was not %d\n", (int)sizeof(qgf_delta_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure this block is valid
|
||||
if (!qgf_validate_block_header(&delta_descriptor.header, QGF_FRAME_DELTA_DESCRIPTOR_TYPEID, (sizeof(qgf_delta_v1_t) - sizeof(qgf_block_header_v1_t)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_validate_frame_data_descriptor(qp_stream_t *stream, uint16_t frame_number) {
|
||||
// Read and validate the data block
|
||||
qgf_data_v1_t data_descriptor;
|
||||
if (qp_stream_read(&data_descriptor, sizeof(qgf_data_v1_t), 1, stream) != 1) {
|
||||
qp_dprintf("Failed to read data_descriptor, expected length was not %d\n", (int)sizeof(qgf_data_v1_t));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qgf_validate_block_header(&data_descriptor.header, QGF_FRAME_DATA_DESCRIPTOR_TYPEID, -1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qgf_validate_stream(qp_stream_t *stream) {
|
||||
uint16_t frame_count;
|
||||
if (!qgf_read_graphics_descriptor(stream, NULL, NULL, &frame_count, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read and validate all the frames (automatically validates the frame offset descriptor in the process)
|
||||
for (uint16_t i = 0; i < frame_count; ++i) {
|
||||
// Validate the frame descriptor block
|
||||
uint8_t bpp;
|
||||
bool has_palette;
|
||||
bool has_delta;
|
||||
if (!qgf_validate_frame_descriptor(stream, i, &bpp, &has_palette, &has_delta)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we've got a palette block, check it
|
||||
if (has_palette && !qgf_validate_palette_descriptor(stream, i, bpp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we've got a delta block, check it
|
||||
if (has_delta && !qgf_validate_delta_descriptor(stream, i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the data block
|
||||
if (!qgf_validate_frame_data_descriptor(stream, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Work out the total size of an image definition, assuming we can read far enough into the file
|
||||
uint32_t qgf_get_total_size(qp_stream_t *stream) {
|
||||
// Get the original location
|
||||
uint32_t oldpos = qp_stream_tell(stream);
|
||||
|
||||
// Read the graphics descriptor, grabbing the size
|
||||
uint32_t total_size;
|
||||
if (!qgf_read_graphics_descriptor(stream, NULL, NULL, NULL, &total_size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore the original location
|
||||
qp_stream_setpos(stream, oldpos);
|
||||
return total_size;
|
||||
}
|
||||
136
quantum/painter/qgf.h
Normal file
136
quantum/painter/qgf.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
// Quantum Graphics File "QGF" File Format.
|
||||
// See https://docs.qmk.fm/#/quantum_painter_qgf for more information.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "qp_stream.h"
|
||||
#include "qp_internal.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QGF structures
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Common block header
|
||||
|
||||
typedef struct QP_PACKED qgf_block_header_v1_t {
|
||||
uint8_t type_id; // See each respective block type below.
|
||||
uint8_t neg_type_id; // Negated type ID, used for detecting parsing errors.
|
||||
uint32_t length : 24; // 24-bit blob length, allowing for block sizes of a maximum of 16MB.
|
||||
} qgf_block_header_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_block_header_v1_t) == 5, "qgf_block_header_v1_t must be 5 bytes in v1 of QGF");
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Graphics descriptor
|
||||
|
||||
#define QGF_GRAPHICS_DESCRIPTOR_TYPEID 0x00
|
||||
|
||||
typedef struct QP_PACKED qgf_graphics_descriptor_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x00, .neg_type_id = (~0x00), .length = 18 }
|
||||
uint32_t magic : 24; // constant, equal to 0x464751 ("QGF")
|
||||
uint8_t qgf_version; // constant, equal to 0x01
|
||||
uint32_t total_file_size; // total size of the entire file, starting at offset zero
|
||||
uint32_t neg_total_file_size; // negated value of total_file_size
|
||||
uint16_t image_width; // in pixels
|
||||
uint16_t image_height; // in pixels
|
||||
uint16_t frame_count; // minimum of 1
|
||||
} qgf_graphics_descriptor_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_graphics_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 18), "qgf_graphics_descriptor_v1_t must be 23 bytes in v1 of QGF");
|
||||
|
||||
#define QGF_MAGIC 0x464751
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Frame offset descriptor
|
||||
|
||||
#define QGF_FRAME_OFFSET_DESCRIPTOR_TYPEID 0x01
|
||||
|
||||
typedef struct QP_PACKED qgf_frame_offsets_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x01, .neg_type_id = (~0x01), .length = (N * sizeof(uint32_t)) }
|
||||
uint32_t offset[0]; // '0' signifies that this struct is immediately followed by the frame offsets
|
||||
} qgf_frame_offsets_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_frame_offsets_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_frame_offsets_v1_t must only contain qgf_block_header_v1_t in v1 of QGF");
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Frame descriptor
|
||||
|
||||
#define QGF_FRAME_DESCRIPTOR_TYPEID 0x02
|
||||
|
||||
typedef struct QP_PACKED qgf_frame_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x02, .neg_type_id = (~0x02), .length = 6 }
|
||||
qp_image_format_t format : 8; // Frame format, see qp.h.
|
||||
uint8_t flags; // Frame flags, see below.
|
||||
painter_compression_t compression_scheme : 8; // Compression scheme, see qp.h.
|
||||
uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented)
|
||||
uint16_t delay; // frame delay time for animations (in units of milliseconds)
|
||||
} qgf_frame_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_frame_v1_t) == (sizeof(qgf_block_header_v1_t) + 6), "qgf_frame_v1_t must be 11 bytes in v1 of QGF");
|
||||
|
||||
#define QGF_FRAME_FLAG_DELTA 0x02
|
||||
#define QGF_FRAME_FLAG_TRANSPARENT 0x01
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Frame palette descriptor
|
||||
|
||||
#define QGF_FRAME_PALETTE_DESCRIPTOR_TYPEID 0x03
|
||||
|
||||
typedef struct QP_PACKED qgf_palette_entry_v1_t {
|
||||
uint8_t h; // hue component: `[0,360)` degrees is mapped to `[0,255]` uint8_t.
|
||||
uint8_t s; // saturation component: `[0,1]` is mapped to `[0,255]` uint8_t.
|
||||
uint8_t v; // value component: `[0,1]` is mapped to `[0,255]` uint8_t.
|
||||
} qgf_palette_entry_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_palette_entry_v1_t) == 3, "Palette entry is not 3 bytes in size");
|
||||
|
||||
typedef struct QP_PACKED qgf_palette_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x03, .neg_type_id = (~0x03), .length = (N * 3 * sizeof(uint8_t)) }
|
||||
qgf_palette_entry_v1_t hsv[0]; // N * hsv, where N is the number of palette entries depending on the frame format in the descriptor
|
||||
} qgf_palette_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_palette_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_palette_v1_t must only contain qgf_block_header_v1_t in v1 of QGF");
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Frame delta descriptor
|
||||
|
||||
#define QGF_FRAME_DELTA_DESCRIPTOR_TYPEID 0x04
|
||||
|
||||
typedef struct QP_PACKED qgf_delta_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x04, .neg_type_id = (~0x04), .length = 8 }
|
||||
uint16_t left; // The left pixel location to draw the delta image
|
||||
uint16_t top; // The top pixel location to draw the delta image
|
||||
uint16_t right; // The right pixel location to to draw the delta image
|
||||
uint16_t bottom; // The bottom pixel location to to draw the delta image
|
||||
} qgf_delta_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_delta_v1_t) == (sizeof(qgf_block_header_v1_t) + 8), "qgf_delta_v1_t must be 13 bytes in v1 of QGF");
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Frame data descriptor
|
||||
|
||||
#define QGF_FRAME_DATA_DESCRIPTOR_TYPEID 0x05
|
||||
|
||||
typedef struct QP_PACKED qgf_data_v1_t {
|
||||
qgf_block_header_v1_t header; // = { .type_id = 0x05, .neg_type_id = (~0x05), .length = N }
|
||||
uint8_t data[0]; // 0 signifies that this struct is immediately followed by the length of data specified in the header
|
||||
} qgf_data_v1_t;
|
||||
|
||||
_Static_assert(sizeof(qgf_data_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_data_v1_t must only contain qgf_block_header_v1_t in v1 of QGF");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QGF API
|
||||
|
||||
uint32_t qgf_get_total_size(qp_stream_t *stream);
|
||||
bool qgf_validate_stream(qp_stream_t *stream);
|
||||
bool qgf_validate_block_header(qgf_block_header_v1_t *desc, uint8_t expected_typeid, int32_t expected_length);
|
||||
bool qgf_read_graphics_descriptor(qp_stream_t *stream, uint16_t *image_width, uint16_t *image_height, uint16_t *frame_count, uint32_t *total_bytes);
|
||||
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette);
|
||||
void qgf_seek_to_frame_descriptor(qp_stream_t *stream, uint16_t frame_number);
|
||||
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay);
|
||||
228
quantum/painter/qp.c
Normal file
228
quantum/painter/qp.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <quantum.h>
|
||||
#include <utf8.h>
|
||||
|
||||
#include "qp_internal.h"
|
||||
#include "qp_comms.h"
|
||||
#include "qp_draw.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal driver validation
|
||||
|
||||
static bool validate_driver_vtable(struct painter_driver_t *driver) {
|
||||
return (driver->driver_vtable && driver->driver_vtable->init && driver->driver_vtable->power && driver->driver_vtable->clear && driver->driver_vtable->viewport && driver->driver_vtable->pixdata && driver->driver_vtable->palette_convert && driver->driver_vtable->append_pixels) ? true : false;
|
||||
}
|
||||
|
||||
static bool validate_comms_vtable(struct painter_driver_t *driver) {
|
||||
return (driver->comms_vtable && driver->comms_vtable->comms_init && driver->comms_vtable->comms_start && driver->comms_vtable->comms_stop && driver->comms_vtable->comms_send) ? true : false;
|
||||
}
|
||||
|
||||
static bool validate_driver_integrity(struct painter_driver_t *driver) {
|
||||
return validate_driver_vtable(driver) && validate_comms_vtable(driver);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_init
|
||||
|
||||
bool qp_init(painter_device_t device, painter_rotation_t rotation) {
|
||||
qp_dprintf("qp_init: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
|
||||
driver->validate_ok = false;
|
||||
if (!validate_driver_integrity(driver)) {
|
||||
qp_dprintf("Failed to validate driver integrity in qp_init\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
driver->validate_ok = true;
|
||||
|
||||
if (!qp_comms_init(device)) {
|
||||
driver->validate_ok = false;
|
||||
qp_dprintf("qp_init: fail (could not init comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_init: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the rotation before init
|
||||
driver->rotation = rotation;
|
||||
|
||||
// Invoke init
|
||||
bool ret = driver->driver_vtable->init(device, rotation);
|
||||
qp_comms_stop(device);
|
||||
qp_dprintf("qp_init: %s\n", ret ? "ok" : "fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_power
|
||||
|
||||
bool qp_power(painter_device_t device, bool power_on) {
|
||||
qp_dprintf("qp_power: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
if (!driver->validate_ok) {
|
||||
qp_dprintf("qp_power: fail (validation_ok == false)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_power: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = driver->driver_vtable->power(device, power_on);
|
||||
qp_comms_stop(device);
|
||||
qp_dprintf("qp_power: %s\n", ret ? "ok" : "fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_clear
|
||||
|
||||
bool qp_clear(painter_device_t device) {
|
||||
qp_dprintf("qp_clear: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
if (!driver->validate_ok) {
|
||||
qp_dprintf("qp_clear: fail (validation_ok == false)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_clear: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = driver->driver_vtable->clear(device);
|
||||
qp_comms_stop(device);
|
||||
qp_dprintf("qp_clear: %s\n", ret ? "ok" : "fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_flush
|
||||
|
||||
bool qp_flush(painter_device_t device) {
|
||||
qp_dprintf("qp_flush: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
if (!driver->validate_ok) {
|
||||
qp_dprintf("qp_flush: fail (validation_ok == false)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_flush: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = driver->driver_vtable->flush(device);
|
||||
qp_comms_stop(device);
|
||||
qp_dprintf("qp_flush: %s\n", ret ? "ok" : "fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_get_geometry
|
||||
|
||||
void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height, painter_rotation_t *rotation, uint16_t *offset_x, uint16_t *offset_y) {
|
||||
qp_dprintf("qp_geometry: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
|
||||
switch (driver->rotation) {
|
||||
default:
|
||||
case QP_ROTATION_0:
|
||||
case QP_ROTATION_180:
|
||||
if (width) {
|
||||
*width = driver->panel_width;
|
||||
}
|
||||
if (height) {
|
||||
*height = driver->panel_height;
|
||||
}
|
||||
break;
|
||||
case QP_ROTATION_90:
|
||||
case QP_ROTATION_270:
|
||||
if (width) {
|
||||
*width = driver->panel_height;
|
||||
}
|
||||
if (height) {
|
||||
*height = driver->panel_width;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rotation) {
|
||||
*rotation = driver->rotation;
|
||||
}
|
||||
|
||||
if (offset_x) {
|
||||
*offset_x = driver->offset_x;
|
||||
}
|
||||
|
||||
if (offset_y) {
|
||||
*offset_y = driver->offset_y;
|
||||
}
|
||||
|
||||
qp_dprintf("qp_geometry: ok\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_set_viewport_offsets
|
||||
|
||||
void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_t offset_y) {
|
||||
qp_dprintf("qp_set_viewport_offsets: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
|
||||
driver->offset_x = offset_x;
|
||||
driver->offset_y = offset_y;
|
||||
|
||||
qp_dprintf("qp_set_viewport_offsets: ok\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_viewport
|
||||
|
||||
bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
|
||||
qp_dprintf("qp_viewport: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
if (!driver->validate_ok) {
|
||||
qp_dprintf("qp_viewport: fail (validation_ok == false)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_viewport: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the viewport
|
||||
bool ret = driver->driver_vtable->viewport(device, left, top, right, bottom);
|
||||
qp_dprintf("qp_viewport: %s\n", ret ? "ok" : "fail");
|
||||
qp_comms_stop(device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API: qp_pixdata
|
||||
|
||||
bool qp_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) {
|
||||
qp_dprintf("qp_pixdata: entry\n");
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
if (!driver->validate_ok) {
|
||||
qp_dprintf("qp_pixdata: fail (validation_ok == false)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!qp_comms_start(device)) {
|
||||
qp_dprintf("qp_pixdata: fail (could not start comms)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = driver->driver_vtable->pixdata(device, pixel_data, native_pixel_count);
|
||||
qp_dprintf("qp_pixdata: %s\n", ret ? "ok" : "fail");
|
||||
qp_comms_stop(device);
|
||||
return ret;
|
||||
}
|
||||
453
quantum/painter/qp.h
Normal file
453
quantum/painter/qp.h
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "deferred_exec.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter global configurables (add to your keyboard's config.h)
|
||||
|
||||
#ifndef QUANTUM_PAINTER_NUM_IMAGES
|
||||
/**
|
||||
* @def This controls the maximum number of images that Quantum Painter can load at any one time. Images can be loaded
|
||||
* using \ref qp_load_image_mem, and can be unloaded by calling \ref qp_close_image. Increasing this number in
|
||||
* order to load more images increases the amount of RAM required. Image data is not held in RAM, just metadata.
|
||||
*/
|
||||
# define QUANTUM_PAINTER_NUM_IMAGES 8
|
||||
#endif // QUANTUM_PAINTER_NUM_IMAGES
|
||||
|
||||
#ifndef QUANTUM_PAINTER_NUM_FONTS
|
||||
/**
|
||||
* @def This controls the maximum number of fonts that Quantum Painter can load. Fonts can be loaded using
|
||||
* \ref qp_load_font_mem, and can be unloaded by calling \ref qp_close_font. Increasing this number in order to
|
||||
* load more fonts increases the amount of RAM required. Font data is not held in RAM, unless
|
||||
* \ref QUANTUM_PAINTER_LOAD_FONTS_TO_RAM is set to TRUE.
|
||||
*/
|
||||
# define QUANTUM_PAINTER_NUM_FONTS 4
|
||||
#endif // QUANTUM_PAINTER_NUM_FONTS
|
||||
|
||||
#ifndef QUANTUM_PAINTER_LOAD_FONTS_TO_RAM
|
||||
/**
|
||||
* @def This controls whether or not fonts should be cached in RAM. Under normal circumstances, fonts can have quite
|
||||
* random access patterns, and due to timing of flash memory or external storage, it may be a significant speedup
|
||||
* moving the font into RAM before use. Defaults to "off", but if it's enabled it will fallback to reading from the
|
||||
* original location if corresponding RAM could not be allocated (such as being too large).
|
||||
*/
|
||||
# define QUANTUM_PAINTER_LOAD_FONTS_TO_RAM FALSE
|
||||
#endif
|
||||
|
||||
#ifndef QUANTUM_PAINTER_CONCURRENT_ANIMATIONS
|
||||
/**
|
||||
* @def This controls the maximum number of animations that Quantum Painter can play simultaneously. Increasing this
|
||||
* number in order to play more animations at the same time increases the amount of RAM required.
|
||||
*/
|
||||
# define QUANTUM_PAINTER_CONCURRENT_ANIMATIONS 4
|
||||
#endif // QUANTUM_PAINTER_CONCURRENT_ANIMATIONS
|
||||
|
||||
#ifndef QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE
|
||||
/**
|
||||
* @def This controls the maximum size of the pixel data buffer used for single blocks of transmission. Larger buffers
|
||||
* means more data is processed at one time, with less frequent transmissions, at the cost of RAM.
|
||||
*/
|
||||
# define QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE 32
|
||||
#endif
|
||||
|
||||
#ifndef QUANTUM_PAINTER_SUPPORTS_256_PALETTE
|
||||
/**
|
||||
* @def This controls whether 256-color palettes are supported. This has relatively hefty requirements on RAM -- at
|
||||
* least 1kB extra is required just to store the palette information, with more required for other metadata.
|
||||
*/
|
||||
# define QUANTUM_PAINTER_SUPPORTS_256_PALETTE FALSE
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter types
|
||||
|
||||
/**
|
||||
* @typedef A handle to a Quantum Painter device, such as an LCD or OLED. Most Quantum Painter APIs require this
|
||||
* argument in order to perform operations on the display.
|
||||
*/
|
||||
typedef const void *painter_device_t;
|
||||
|
||||
/**
|
||||
* @typedef The desired rotation of a panel. Used as a parameter to \ref qp_init, and can be queried by
|
||||
* \ref qp_get_geometry.
|
||||
*/
|
||||
typedef enum { QP_ROTATION_0, QP_ROTATION_90, QP_ROTATION_180, QP_ROTATION_270 } painter_rotation_t;
|
||||
|
||||
/**
|
||||
* @typedef A descriptor for a Quantum Painter image.
|
||||
*/
|
||||
typedef struct painter_image_desc_t {
|
||||
uint16_t width; ///< Image width
|
||||
uint16_t height; ///< Image height
|
||||
uint16_t frame_count; ///< Number of frames in this image
|
||||
} painter_image_desc_t;
|
||||
|
||||
/**
|
||||
* @typedef A handle to a Quantum Painter image.
|
||||
*/
|
||||
typedef const painter_image_desc_t *painter_image_handle_t;
|
||||
|
||||
/**
|
||||
* @typedef A descriptor for a Quantum Painter font.
|
||||
*/
|
||||
typedef struct painter_font_desc_t {
|
||||
uint8_t line_height; ///< The number of pixels in height for each line
|
||||
} painter_font_desc_t;
|
||||
|
||||
/**
|
||||
* @typedef A handle to a Quantum Painter font.
|
||||
*/
|
||||
typedef const painter_font_desc_t *painter_font_handle_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter External API
|
||||
|
||||
/**
|
||||
* Initialize a device and set its rotation.
|
||||
*
|
||||
* @param device[in] the handle of the device to initialize
|
||||
* @param rotation[in] the rotation to use
|
||||
* @return true if initialization succeeded
|
||||
* @return false if initialization failed
|
||||
*/
|
||||
bool qp_init(painter_device_t device, painter_rotation_t rotation);
|
||||
|
||||
/**
|
||||
* Controls whether a display is on or off.
|
||||
*
|
||||
* @note If backlighting is used to control brightness (such as for an LCD), it will need to be handled external to
|
||||
* Quantum Painter.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param power_on[in] whether or not the device should be on
|
||||
* @return true if controlling the power state succeeded
|
||||
* @return false if controlling the power state failed
|
||||
*/
|
||||
bool qp_power(painter_device_t device, bool power_on);
|
||||
|
||||
/**
|
||||
* Clears a device's screen.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @return true if clearing the screen succeeded
|
||||
* @return false if clearing the screen failed
|
||||
*/
|
||||
bool qp_clear(painter_device_t device);
|
||||
|
||||
/**
|
||||
* Transmits any outstanding data to the screen in order to persist all changes to the display.
|
||||
*
|
||||
* @note Drivers without internal framebuffers will likely ignore this API.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @return true if flushing changes to the screen succeeded
|
||||
* @return false if flushing changes to the screen failed
|
||||
*/
|
||||
bool qp_flush(painter_device_t device);
|
||||
|
||||
/**
|
||||
* Retrieves the size, rotation, and offsets for the display.
|
||||
*
|
||||
* @note Any arguments of NULL will be ignored.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param width[out] the device's width
|
||||
* @param height[out] the device's height
|
||||
* @param rotation[out] the device's rotation
|
||||
* @param offset_x[out] the device's x-offset applied while drawing
|
||||
* @param offset_y[out] the device's y-offset applied while drawing
|
||||
*/
|
||||
void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height, painter_rotation_t *rotation, uint16_t *offset_x, uint16_t *offset_y);
|
||||
|
||||
/**
|
||||
* Allows repositioning of the viewport if the panel geometry offsets are non-zero.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param offset_x[in] the device's x-offset applied while drawing
|
||||
* @param offset_y[in] the device's y-offset applied while drawing
|
||||
*/
|
||||
void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_t offset_y);
|
||||
|
||||
/**
|
||||
* Sets a pixel to the specified color.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position to draw onto the device
|
||||
* @param y[in] the y-position to draw onto the device
|
||||
* @param hue[in] the hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat[in] the saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val[in] the value to use, with 0-100% mapped to 0-255
|
||||
* @return true if setting the pixel succeeded
|
||||
* @return false if setting the pixel failed
|
||||
*/
|
||||
bool qp_setpixel(painter_device_t device, uint16_t x, uint16_t y, uint8_t hue, uint8_t sat, uint8_t val);
|
||||
|
||||
/**
|
||||
* Draws a line using the specified color.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x0[in] the device's x-position to start
|
||||
* @param y0[in] the device's y-position to start
|
||||
* @param x1[in] the device's x-position to finish
|
||||
* @param y1[in] the device's y-position to finish
|
||||
* @param hue[in] the hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat[in] the saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val[in] the value to use, with 0-100% mapped to 0-255
|
||||
* @return true if drawing the line succeeded
|
||||
* @return false if drawing the line failed
|
||||
*/
|
||||
bool qp_line(painter_device_t device, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t hue, uint8_t sat, uint8_t val);
|
||||
|
||||
/**
|
||||
* Draws a rectangle using the specified color, optionally filled.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param left[in] the device's x-position to start
|
||||
* @param top[in] the device's y-position to start
|
||||
* @param right[in] the device's x-position to finish
|
||||
* @param bottom[in] the device's y-position to finish
|
||||
* @param hue[in] the hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat[in] the saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val[in] the value to use, with 0-100% mapped to 0-255
|
||||
* @param filled[in] whether the rectangle should be filled
|
||||
* @return true if drawing the rectangle succeeded
|
||||
* @return false if drawing the rectangle failed
|
||||
*/
|
||||
bool qp_rect(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
|
||||
|
||||
/**
|
||||
* Draws a circle using the specified color, optionally filled.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position of the centre of the circle to draw onto the device
|
||||
* @param y[in] the y-position of the centre of the circle to draw onto the device
|
||||
* @param radius[in] the radius of the circle to draw
|
||||
* @param hue[in] the hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat[in] the saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val[in] the value to use, with 0-100% mapped to 0-255
|
||||
* @param filled[in] whether the circle should be filled
|
||||
* @return true if drawing the circle succeeded
|
||||
* @return false if drawing the circle failed
|
||||
*/
|
||||
bool qp_circle(painter_device_t device, uint16_t x, uint16_t y, uint16_t radius, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
|
||||
|
||||
/**
|
||||
* Draws a ellipse using the specified color, optionally filled.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position of the centre of the ellipse to draw onto the device
|
||||
* @param y[in] the y-position of the centre of the ellipse to draw onto the device
|
||||
* @param sizex[in] the horizontal size of the ellipse
|
||||
* @param sizey[in] the vertical size of the ellipse
|
||||
* @param hue[in] the hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat[in] the saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val[in] the value to use, with 0-100% mapped to 0-255
|
||||
* @param filled[in] whether the ellipse should be filled
|
||||
* @return true if drawing the ellipse succeeded
|
||||
* @return false if drawing the ellipse failed
|
||||
*/
|
||||
bool qp_ellipse(painter_device_t device, uint16_t x, uint16_t y, uint16_t sizex, uint16_t sizey, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
|
||||
|
||||
/**
|
||||
* Sets up the location on the display to stream raw pixel data to the display, using \ref qp_pixdata.
|
||||
*
|
||||
* @note This is for advanced uses only, and should not be required for normal Quantum Painter functionality.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param left[in] the device's x-position to start
|
||||
* @param top[in] the device's y-position to start
|
||||
* @param right[in] the device's x-position to finish
|
||||
* @param bottom[in] the device's y-position to finish
|
||||
* @return true if setting the viewport succeeded
|
||||
* @return false if setting the viewport failed
|
||||
*/
|
||||
bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);
|
||||
|
||||
/**
|
||||
* Streams raw pixel data (in the native panel format) to the area previously set by \ref qp_viewport.
|
||||
*
|
||||
* @note This is for advanced uses only, and should not be required for normal Quantum Painter functionality.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param pixel_data[in] pointer to buffer data
|
||||
* @param native_pixel_count[in] the number of pixels to transmit
|
||||
* @return true if streaming of data succeeded
|
||||
* @return false if streaming of data failed
|
||||
*/
|
||||
bool qp_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
|
||||
|
||||
/**
|
||||
* Loads an image into memory.
|
||||
*
|
||||
* @note Images can be unloaded by calling \ref qp_close_image.
|
||||
*
|
||||
* @param buffer[in] the image data to load
|
||||
* @return an image handle usable with \ref qp_drawimage, \ref qp_drawimage_recolor, \ref qp_animate, and
|
||||
* \ref qp_animate_recolor.
|
||||
* @return NULL if loading the image failed
|
||||
*/
|
||||
painter_image_handle_t qp_load_image_mem(const void *buffer);
|
||||
|
||||
/**
|
||||
* Closes an image handle when no longer in use.
|
||||
*
|
||||
* @param image[in] the handle of the image to unload
|
||||
* @return true if unloading the image succeeded
|
||||
* @return false if unloading the image failed
|
||||
*/
|
||||
bool qp_close_image(painter_image_handle_t image);
|
||||
|
||||
/**
|
||||
* Draws an image to the display.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the image should be drawn onto the device
|
||||
* @param y[in] the y-position where the image should be drawn onto the device
|
||||
* @param image[in] the handle of the image to draw
|
||||
* @return true if drawing the image succeeded
|
||||
* @return false if drawing the image failed
|
||||
*/
|
||||
bool qp_drawimage(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
|
||||
|
||||
/**
|
||||
* Draws an image to the display, recoloring monochrome images to the desired foreground/background.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the image should be drawn onto the device
|
||||
* @param y[in] the y-position where the image should be drawn onto the device
|
||||
* @param image[in] the handle of the image to draw
|
||||
* @param hue_fg[in] the foreground hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_fg[in] the foreground saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_fg[in] the foreground value to use, with 0-100% mapped to 0-255
|
||||
* @param hue_bg[in] the background hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_bg[in] the background saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_bg[in] the background value to use, with 0-100% mapped to 0-255
|
||||
* @return true if drawing the image succeeded
|
||||
* @return false if drawing the image failed
|
||||
*/
|
||||
bool qp_drawimage_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
|
||||
|
||||
/**
|
||||
* Draws an animation to the display.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the image should be drawn onto the device
|
||||
* @param y[in] the y-position where the image should be drawn onto the device
|
||||
* @param image[in] the handle of the image to draw
|
||||
* @return the \ref deferred_token to use with \ref qp_stop_animation in order to stop animating
|
||||
* @return INVALID_DEFERRED_TOKEN if animating the image failed
|
||||
*/
|
||||
deferred_token qp_animate(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
|
||||
|
||||
/**
|
||||
* Draws an animation to the display, recoloring monochrome images to the desired foreground/background.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the image should be drawn onto the device
|
||||
* @param y[in] the y-position where the image should be drawn onto the device
|
||||
* @param image[in] the handle of the image to draw
|
||||
* @param hue_fg[in] the foreground hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_fg[in] the foreground saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_fg[in] the foreground value to use, with 0-100% mapped to 0-255
|
||||
* @param hue_bg[in] the background hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_bg[in] the background saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_bg[in] the background value to use, with 0-100% mapped to 0-255
|
||||
* @return the \ref deferred_token to use with \ref qp_stop_animation in order to stop animating
|
||||
* @return INVALID_DEFERRED_TOKEN if animating the image failed
|
||||
*/
|
||||
deferred_token qp_animate_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
|
||||
|
||||
/**
|
||||
* Cancels a running animation.
|
||||
*
|
||||
* @param anim_token[in] the animation token returned by \ref qp_animate, or \ref qp_animate_recolor.
|
||||
*/
|
||||
void qp_stop_animation(deferred_token anim_token);
|
||||
|
||||
/**
|
||||
* Loads a font into memory.
|
||||
*
|
||||
* @note Fonts can be unloaded by calling \ref qp_close_font.
|
||||
*
|
||||
* @param buffer[in] the font data to load
|
||||
* @return an image handle usable with \ref qp_textwidth, \ref qp_drawtext, and \ref qp_drawtext_recolor.
|
||||
* @return NULL if loading the font failed
|
||||
*/
|
||||
painter_font_handle_t qp_load_font_mem(const void *buffer);
|
||||
|
||||
/**
|
||||
* Closes a font handle when no longer in use.
|
||||
*
|
||||
* @param font[in] the handle of the font to unload
|
||||
* @return true if unloading the font succeeded
|
||||
* @return false if unloading the font failed
|
||||
*/
|
||||
bool qp_close_font(painter_font_handle_t font);
|
||||
|
||||
/**
|
||||
* Measures the width (in pixels) of the supplied string, given the specified font.
|
||||
*
|
||||
* @param font[in] the handle of the font
|
||||
* @param str[in] the string to measure
|
||||
* @return the width (in pixels) needed to draw the specified string
|
||||
*/
|
||||
int16_t qp_textwidth(painter_font_handle_t font, const char *str);
|
||||
|
||||
/**
|
||||
* Draws text to the display.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the text should be drawn onto the device
|
||||
* @param y[in] the y-position where the text should be drawn onto the device
|
||||
* @param font[in] the handle of the font
|
||||
* @param str[in] the string to draw
|
||||
* @return the width (in pixels) used when drawing the specified string
|
||||
*/
|
||||
int16_t qp_drawtext(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str);
|
||||
|
||||
/**
|
||||
* Draws text to the display, recoloring monochrome fonts to the desired foreground/background.
|
||||
*
|
||||
* @param device[in] the handle of the device to control
|
||||
* @param x[in] the x-position where the text should be drawn onto the device
|
||||
* @param y[in] the y-position where the text should be drawn onto the device
|
||||
* @param font[in] the handle of the font
|
||||
* @param str[in] the string to draw
|
||||
* @param hue_fg[in] the foreground hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_fg[in] the foreground saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_fg[in] the foreground value to use, with 0-100% mapped to 0-255
|
||||
* @param hue_bg[in] the background hue to use, with 0-360 mapped to 0-255
|
||||
* @param sat_bg[in] the background saturation to use, with 0-100% mapped to 0-255
|
||||
* @param val_bg[in] the background value to use, with 0-100% mapped to 0-255
|
||||
* @return the width (in pixels) used when drawing the specified string
|
||||
*/
|
||||
int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter Drivers
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ILI9163_ENABLE
|
||||
# include "qp_ili9163.h"
|
||||
#endif // QUANTUM_PAINTER_ILI9163_ENABLE
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ILI9341_ENABLE
|
||||
# include "qp_ili9341.h"
|
||||
#endif // QUANTUM_PAINTER_ILI9341_ENABLE
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ST7789_ENABLE
|
||||
# include "qp_st7789.h"
|
||||
#endif // QUANTUM_PAINTER_ST7789_ENABLE
|
||||
|
||||
#ifdef QUANTUM_PAINTER_GC9A01_ENABLE
|
||||
# include "qp_gc9a01.h"
|
||||
#endif // QUANTUM_PAINTER_GC9A01_ENABLE
|
||||
|
||||
#ifdef QUANTUM_PAINTER_SSD1351_ENABLE
|
||||
# include "qp_ssd1351.h"
|
||||
#endif // QUANTUM_PAINTER_SSD1351_ENABLE
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue