Merge remote-tracking branch 'qmk/master' into merge-2022-07-11
This commit is contained in:
commit
fde0c10bae
7121 files changed
+170387
-28117
No files matched your search
+67
-28
@@ -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);
|
||||
|
||||
+60
-22
@@ -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
|
||||
|
||||
|
||||
+17
-21
@@ -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
|
||||
|
||||
@@ -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) {}
|
||||
@@ -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);
|
||||
+53
-49
@@ -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);
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
+108
-44
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-1
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
+31
-49
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
+1
-1
@@ -321,7 +321,7 @@ void haptic_play(void) {
|
||||
DRV_pulse(play_eff);
|
||||
#endif
|
||||
#ifdef SOLENOID_ENABLE
|
||||
solenoid_fire();
|
||||
solenoid_fire_handler();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+31
-6
@@ -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();
|
||||
}
|
||||
+13
-4
@@ -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);
|
||||
+13
-16
@@ -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
|
||||
|
||||
+29
-7
@@ -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
|
||||
+11
-2
@@ -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;
|
||||
}
|
||||
+2
-2
@@ -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
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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,
|
||||
|
||||
+21
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+21
-1
@@ -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,
|
||||
|
||||
+21
-1
@@ -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,
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_italian_osx_ansi.h"
|
||||
#include "keymap_italian_mac_ansi.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keymap_italian_osx_iso.h"
|
||||
#include "keymap_italian_mac_iso.h"
|
||||
#include "quantum.h"
|
||||
|
||||
// clang-format off
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+21
-1
@@ -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,
|
||||
|
||||
+21
-1
@@ -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,
|
||||
+21
-1
@@ -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
|
||||
|
||||
|
||||
+7
-4
@@ -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;
|
||||
|
||||
+19
-10
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Loaded 100 of 7121 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user