summaryrefslogtreecommitdiffstats
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/audio/song_list.h8
-rw-r--r--quantum/config_common.h9
-rw-r--r--quantum/dynamic_macro.h231
-rw-r--r--quantum/keycode_config.h5
-rw-r--r--quantum/keymap.h26
-rw-r--r--quantum/keymap_common.c4
-rw-r--r--quantum/keymap_extras/keymap_bepo.h4
-rw-r--r--quantum/keymap_extras/keymap_br_abnt2.h58
-rw-r--r--quantum/keymap_extras/keymap_canadian_multilingual.h255
-rw-r--r--quantum/keymap_extras/keymap_dvorak.h19
-rw-r--r--quantum/keymap_extras/keymap_dvp.h82
-rw-r--r--quantum/keymap_extras/keymap_fr_ch.h2
-rw-r--r--quantum/keymap_extras/keymap_french.h4
-rw-r--r--quantum/keymap_extras/keymap_german.h2
-rw-r--r--quantum/keymap_extras/keymap_german_ch.h2
-rw-r--r--quantum/keymap_extras/keymap_nordic.h4
-rw-r--r--quantum/keymap_extras/keymap_norwegian.h2
-rw-r--r--quantum/keymap_extras/keymap_russian.h77
-rw-r--r--quantum/keymap_extras/keymap_spanish.h2
-rw-r--r--quantum/keymap_extras/keymap_uk.h4
-rw-r--r--quantum/keymap_extras/keymap_unicode_cyrillic.h163
-rwxr-xr-xquantum/light_ws2812.c25
-rw-r--r--quantum/process_keycode/process_midi.c28
-rw-r--r--quantum/process_keycode/process_music.c7
-rw-r--r--quantum/process_keycode/process_tap_dance.c144
-rw-r--r--quantum/process_keycode/process_tap_dance.h52
-rw-r--r--quantum/process_keycode/process_unicode.c261
-rw-r--r--quantum/process_keycode/process_unicode.h54
-rw-r--r--quantum/quantum.c266
-rw-r--r--quantum/quantum.h6
-rw-r--r--quantum/rgblight.c743
-rw-r--r--quantum/rgblight.h13
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c3
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h3
-rw-r--r--quantum/serial_link/protocol/transport.c4
-rw-r--r--quantum/serial_link/protocol/transport.h7
-rw-r--r--quantum/serial_link/tests/byte_stuffer_tests.cpp (renamed from quantum/serial_link/tests/byte_stuffer_tests.c)313
-rw-r--r--quantum/serial_link/tests/frame_router_tests.c231
-rw-r--r--quantum/serial_link/tests/frame_router_tests.cpp229
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.cpp (renamed from quantum/serial_link/tests/frame_validator_tests.c)90
-rw-r--r--quantum/serial_link/tests/rules.mk22
-rw-r--r--quantum/serial_link/tests/testlist.mk6
-rw-r--r--quantum/serial_link/tests/transport_tests.c168
-rw-r--r--quantum/serial_link/tests/transport_tests.cpp188
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.cpp (renamed from quantum/serial_link/tests/triple_buffered_object_tests.c)52
-rw-r--r--quantum/template/Makefile76
-rw-r--r--quantum/template/readme.md10
-rw-r--r--quantum/template/rules.mk67
-rw-r--r--quantum/template/template.c2
-rw-r--r--quantum/variable_trace.c110
-rw-r--r--quantum/variable_trace.h34
-rw-r--r--quantum/visualizer/led_test.c4
-rw-r--r--quantum/visualizer/visualizer.c14
-rw-r--r--quantum/visualizer/visualizer.h2
-rw-r--r--quantum/visualizer/visualizer.mk36
55 files changed, 2929 insertions, 1304 deletions
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
index fc6fcdeef1..8022ca6729 100644
--- a/quantum/audio/song_list.h
+++ b/quantum/audio/song_list.h
@@ -28,6 +28,14 @@
Q__NOTE(_E4), Q__NOTE(_C4), \
Q__NOTE(_E4),
+/* Requires: PLAY_NOTE_ARRAY(..., ..., STACCATO); */
+#define IN_LIKE_FLINT \
+ E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4), \
+ E__NOTE(_AS4), E__NOTE(_B4), QD_NOTE(_CS4), \
+ E__NOTE(_B4), E__NOTE(_CS4), QD_NOTE(_DS4), \
+ E__NOTE(_CS4), E__NOTE(_B4), QD_NOTE(_AS4), \
+ E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4),
+
#define GOODBYE_SOUND \
E__NOTE(_E7), \
E__NOTE(_A6), \
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 09a4fe7010..8ed5f4a106 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -45,6 +45,15 @@
#define F5 0xF5
#define F6 0xF6
#define F7 0xF7
+#define A0 0x00
+#define A1 0x01
+#define A2 0x02
+#define A3 0x03
+#define A4 0x04
+#define A5 0x05
+#define A6 0x06
+#define A7 0x07
+
/* USART configuration */
#ifdef BLUETOOTH_ENABLE
diff --git a/quantum/dynamic_macro.h b/quantum/dynamic_macro.h
new file mode 100644
index 0000000000..e6dbc5b9c1
--- /dev/null
+++ b/quantum/dynamic_macro.h
@@ -0,0 +1,231 @@
+/* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */
+#ifndef DYNAMIC_MACROS_H
+#define DYNAMIC_MACROS_H
+
+#include "action_layer.h"
+
+#ifndef DYNAMIC_MACRO_SIZE
+/* May be overridden with a custom value. Be aware that the effective
+ * macro length is half of this value: each keypress is recorded twice
+ * because of the down-event and up-event. This is not a bug, it's the
+ * intended behavior.
+ *
+ * Usually it should be fine to set the macro size to at least 256 but
+ * there have been reports of it being too much in some users' cases,
+ * so 128 is considered a safe default.
+ */
+#define DYNAMIC_MACRO_SIZE 128
+#endif
+
+/* DYNAMIC_MACRO_RANGE must be set as the last element of user's
+ * "planck_keycodes" enum prior to including this header. This allows
+ * us to 'extend' it.
+ */
+enum dynamic_macro_keycodes {
+ DYN_REC_START1 = DYNAMIC_MACRO_RANGE,
+ DYN_REC_START2,
+ DYN_MACRO_PLAY1,
+ DYN_MACRO_PLAY2,
+};
+
+/* Blink the LEDs to notify the user about some event. */
+void dynamic_macro_led_blink(void)
+{
+ backlight_toggle();
+ _delay_ms(100);
+ backlight_toggle();
+}
+
+/**
+ * Start recording of the dynamic macro.
+ *
+ * @param[out] macro_pointer The new macro buffer iterator.
+ * @param[in] macro_buffer The macro buffer used to initialize macro_pointer.
+ */
+void dynamic_macro_record_start(
+ keyrecord_t **macro_pointer, keyrecord_t *macro_buffer)
+{
+ dynamic_macro_led_blink();
+
+ clear_keyboard();
+ layer_clear();
+ *macro_pointer = macro_buffer;
+}
+
+/**
+ * Play the dynamic macro.
+ *
+ * @param macro_buffer[in] The beginning of the macro buffer being played.
+ * @param macro_end[in] The element after the last macro buffer element.
+ * @param direction[in] Either +1 or -1, which way to iterate the buffer.
+ */
+void dynamic_macro_play(
+ keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction)
+{
+ uint32_t saved_layer_state = layer_state;
+
+ clear_keyboard();
+ layer_clear();
+
+ while (macro_buffer != macro_end) {
+ process_record(macro_buffer);
+ macro_buffer += direction;
+ }
+
+ clear_keyboard();
+
+ layer_state = saved_layer_state;
+}
+
+/**
+ * Record a single key in a dynamic macro.
+ *
+ * @param macro_pointer[in,out] The current buffer position.
+ * @param macro_end2[in] The end of the other macro which shouldn't be overwritten.
+ * @param direction[in] Either +1 or -1, which way to iterate the buffer.
+ * @param record[in] The current keypress.
+ */
+void dynamic_macro_record_key(
+ keyrecord_t **macro_pointer,
+ keyrecord_t *macro_end2,
+ int8_t direction,
+ keyrecord_t *record)
+{
+ if (*macro_pointer + direction != macro_end2) {
+ **macro_pointer = *record;
+ *macro_pointer += direction;
+ } else {
+ /* Notify about the end of buffer. The blinks are paired
+ * because they should happen on both down and up events. */
+ backlight_toggle();
+ }
+}
+
+/**
+ * End recording of the dynamic macro. Essentially just update the
+ * pointer to the end of the macro.
+ */
+void dynamic_macro_record_end(keyrecord_t *macro_pointer, keyrecord_t **macro_end)
+{
+ dynamic_macro_led_blink();
+
+ *macro_end = macro_pointer;
+}
+
+/* Handle the key events related to the dynamic macros. Should be
+ * called from process_record_user() like this:
+ *
+ * bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ * if (!process_record_dynamic_macro(keycode, record)) {
+ * return false;
+ * }
+ * <...THE REST OF THE FUNCTION...>
+ * }
+ */
+bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record)
+{
+ /* Both macros use the same buffer but read/write on different
+ * ends of it.
+ *
+ * Macro1 is written left-to-right starting from the beginning of
+ * the buffer.
+ *
+ * Macro2 is written right-to-left starting from the end of the
+ * buffer.
+ *
+ * &macro_buffer macro_end
+ * v v
+ * +------------------------------------------------------------+
+ * |>>>>>> MACRO1 >>>>>>| |<<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<|
+ * +------------------------------------------------------------+
+ * ^ ^
+ * r_macro_end r_macro_buffer
+ *
+ * During the recording when one macro encounters the end of the
+ * other macro, the recording is stopped. Apart from this, there
+ * are no arbitrary limits for the macros' length in relation to
+ * each other: for example one can either have two medium sized
+ * macros or one long macro and one short macro. Or even one empty
+ * and one using the whole buffer.
+ */
+ static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE];
+
+ /* Pointer to the first buffer element after the first macro.
+ * Initially points to the very beginning of the buffer since the
+ * macro is empty. */
+ static keyrecord_t *macro_end = macro_buffer;
+
+ /* The other end of the macro buffer. Serves as the beginning of
+ * the second macro. */
+ static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
+
+ /* Like macro_end but for the second macro. */
+ static keyrecord_t *r_macro_end = r_macro_buffer;
+
+ /* A persistent pointer to the current macro position (iterator)
+ * used during the recording. */
+ static keyrecord_t *macro_pointer = NULL;
+
+ /* 0 - no macro is being recorded right now
+ * 1,2 - either macro 1 or 2 is being recorded */
+ static uint8_t macro_id = 0;
+
+ if (macro_id == 0) {
+ /* No macro recording in progress. */
+ if (!record->event.pressed) {
+ switch (keycode) {
+ case DYN_REC_START1:
+ dynamic_macro_record_start(&macro_pointer, macro_buffer);
+ macro_id = 1;
+ return false;
+ case DYN_REC_START2:
+ dynamic_macro_record_start(&macro_pointer, r_macro_buffer);
+ macro_id = 2;
+ return false;
+ case DYN_MACRO_PLAY1:
+ dynamic_macro_play(macro_buffer, macro_end, +1);
+ return false;
+ case DYN_MACRO_PLAY2:
+ dynamic_macro_play(r_macro_buffer, r_macro_end, -1);
+ return false;
+ }
+ }
+ } else {
+ /* A macro is being recorded right now. */
+ switch (keycode) {
+ case MO(_DYN):
+ /* Use the layer key used to access the macro recording as
+ * a stop button. */
+ if (record->event.pressed) { /* Ignore the initial release
+ * just after the recoding
+ * starts. */
+ switch (macro_id) {
+ case 1:
+ dynamic_macro_record_end(macro_pointer, &macro_end);
+ break;
+ case 2:
+ dynamic_macro_record_end(macro_pointer, &r_macro_end);
+ break;
+ }
+ macro_id = 0;
+ }
+ return false;
+ default:
+ /* Store the key in the macro buffer and process it normally. */
+ switch (macro_id) {
+ case 1:
+ dynamic_macro_record_key(&macro_pointer, r_macro_end, +1, record);
+ break;
+ case 2:
+ dynamic_macro_record_key(&macro_pointer, macro_end, -1, record);
+ break;
+ }
+ return true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+#endif
diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h
index 6216eefc90..c15b0d32f8 100644
--- a/quantum/keycode_config.h
+++ b/quantum/keycode_config.h
@@ -1,6 +1,9 @@
#include "eeconfig.h"
#include "keycode.h"
+#ifndef KEYCODE_CONFIG_H
+#define KEYCODE_CONFIG_H
+
uint16_t keycode_config(uint16_t keycode);
/* NOTE: Not portable. Bit field order depends on implementation */
@@ -19,3 +22,5 @@ typedef union {
} keymap_config_t;
extern keymap_config_t keymap_config;
+
+#endif /* KEYCODE_CONFIG_H */
diff --git a/quantum/keymap.h b/quantum/keymap.h
index 73f99f8211..a01bbfbd14 100644
--- a/quantum/keymap.h
+++ b/quantum/keymap.h
@@ -84,6 +84,10 @@ enum quantum_keycodes {
QK_MOD_TAP_MAX = 0x6FFF,
QK_TAP_DANCE = 0x7100,
QK_TAP_DANCE_MAX = 0x71FF,
+#ifdef UNICODEMAP_ENABLE
+ QK_UNICODE_MAP = 0x7800,
+ QK_UNICODE_MAP_MAX = 0x7FFF,
+#endif
#ifdef UNICODE_ENABLE
QK_UNICODE = 0x8000,
QK_UNICODE_MAX = 0xFFFF,
@@ -111,6 +115,7 @@ enum quantum_keycodes {
MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
MAGIC_UNHOST_NKRO,
MAGIC_UNSWAP_ALT_GUI,
+ MAGIC_TOGGLE_NKRO,
// Leader key
#ifndef DISABLE_LEADER
@@ -157,6 +162,16 @@ enum quantum_keycodes {
BL_TOGG,
BL_STEP,
+ // RGB functionality
+ RGB_TOG,
+ RGB_MOD,
+ RGB_HUI,
+ RGB_HUD,
+ RGB_SAI,
+ RGB_SAD,
+ RGB_VAI,
+ RGB_VAD,
+
// Left shift, open paren
KC_LSPO,
@@ -180,6 +195,7 @@ enum quantum_keycodes {
#define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI)
#define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT)
#define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI)
+#define ALTG(kc) (kc | QK_RCTL | QK_RALT)
#define MOD_HYPR 0xf
#define MOD_MEH 0x7
@@ -284,7 +300,10 @@ enum quantum_keycodes {
// ON_PRESS = 1
// ON_RELEASE = 2
// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default.
-#define TO(layer, when) (layer | QK_TO | (when << 0x4))
+// In fact, we changed it to assume ON_PRESS for sanity/simplicity. If needed, you can add your own
+// keycode modeled after the old version, kept below for this.
+/* #define TO(layer, when) (layer | QK_TO | (when << 0x4)) */
+#define TO(layer) (layer | QK_TO | (ON_PRESS << 0x4))
// Momentary switch layer - 256 layer max
#define MO(layer) (layer | QK_MOMENTARY)
@@ -299,7 +318,7 @@ enum quantum_keycodes {
#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
// One-shot mod
-#define OSM(layer) (layer | QK_ONE_SHOT_MOD)
+#define OSM(mod) (mod | QK_ONE_SHOT_MOD)
// M-od, T-ap - 256 keycode max
#define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8))
@@ -324,5 +343,8 @@ enum quantum_keycodes {
#define UC(n) UNICODE(n)
#endif
+#ifdef UNICODEMAP_ENABLE
+ #define X(n) (n | QK_UNICODE_MAP)
+#endif
#endif
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index 76872ac592..833e5a8f8d 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -30,7 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "quantum.h"
#ifdef MIDI_ENABLE
- #include "keymap_midi.h"
+ #include "process_midi.h"
#endif
extern keymap_config_t keymap_config;
@@ -62,7 +62,7 @@ action_t action_for_key(uint8_t layer, keypos_t key)
case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
break;
- case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
+ case KC_AUDIO_MUTE ... KC_MEDIA_REWIND:
action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
break;
case KC_MS_UP ... KC_MS_ACCEL2:
diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h
index 4c30960547..e5ef39552a 100644
--- a/quantum/keymap_extras/keymap_bepo.h
+++ b/quantum/keymap_extras/keymap_bepo.h
@@ -118,7 +118,7 @@
// Fourth row
#define BP_COLON LSFT(BP_DOT) // :
#define BP_COLN BP_COLON
-#define BP_QUESTION LSFT(BP_QUOTE) // ?
+#define BP_QUESTION LSFT(BP_APOS) // ?
#define BP_QEST BP_QUESTION
// Space bar
@@ -183,7 +183,7 @@
// Third row
#define BP_AE_LIGATURE ALTGR(BP_A) // æ
#define BP_AE BP_AE_LIGATURE
-#define BP_U_GRAVE AGR(BP_U) // ù
+#define BP_U_GRAVE ALTGR(BP_U) // ù
#define BP_UGRV BP_U_GRAVE
#define BP_DEAD_TREMA ALTGR(BP_I) // dead ¨ (trema/umlaut/diaresis)
#define BP_DTRM BP_DEAD_TREMA
diff --git a/quantum/keymap_extras/keymap_br_abnt2.h b/quantum/keymap_extras/keymap_br_abnt2.h
new file mode 100644
index 0000000000..0df177721d
--- /dev/null
+++ b/quantum/keymap_extras/keymap_br_abnt2.h
@@ -0,0 +1,58 @@
+#ifndef KEYMAP_BR_ABNT2_H
+#define KEYMAP_BR_ABNT2_H
+
+#include "keymap_common.h"
+
+/* Scan codes for the Brazilian ABNT2 keyboard layout */
+
+#define BR_CCDL KC_SCLN // Ç same scancode as ;: on US layout
+#define BR_SCLN KC_SLSH // ;: same scancode as /? on US layout
+#define BR_QUOT KC_GRV // '" same scancode as `~ on US layout
+#define BR_TILD KC_QUOT // ~^ dead keys, same scancode as '" on US layout
+#define BR_ACUT KC_LBRC // ´` dead keys, same scancode as [{ on US layout
+#define BR_LBRC KC_RBRC // [{ same scancode as ]} on US layout
+#define BR_RBRC KC_BSLS // ]} same scancode as \| on US layout
+#define BR_BSLS KC_NUBS // \| uses the non-US hash scancode (#~, sometimes §±)
+#define BR_SLSH KC_INT1 // /? uses the INTL1 scancode
+
+#define BR_COLN LSFT(BR_SCLN) // shifted :
+#define BR_DQT LSFT(BR_QUOT) // shifted "
+#define BR_CIRC LSFT(BR_TILD) // shifted ^ (dead key)
+#define BR_GRAV LSFT(BR_ACUT) // shifted ` (dead key)
+#define BR_LCBR LSFT(BR_LBRC) // shifted {
+#define BR_RCBR LSFT(BR_RBRC) // shifted }
+#define BR_PIPE LSFT(BR_BSLS) // shifted |
+#define BR_QUES LSFT(BR_SLSH) // shifted ?
+#define BR_TRMA LSFT(KC_6) // shifted ¨ (dead key - trema accent)
+
+// On the ABNT2 the keypad comma and the keypad dot scancodes are switched
+// (presumably because in Brazil comma is used as the decimal separator)
+#define BR_KPDT KC_KP_COMMA // keypad .
+#define BR_KPCM KC_KP_DOT // keypad ,
+
+#define BR_1UP LALT(KC_1) // 1 superscript ¹ alt+1
+#define BR_2UP LALT(KC_2) // 2 superscript ² alt+2
+#define BR_3UP LALT(KC_3) // 3 superscript ³ alt+3
+#define BR_PND LALT(KC_4) // Pound sign £ alt+4
+#define BR_CENT LALT(KC_5) // Cent sign ¢ alt+5
+#define BR_NOT LALT(KC_6) // Not sign ¬ alt+6
+#define BR_SECT LALT(KC_EQL) // Section sign § alt+=
+#define BR_FORD LALT(BR_LBRC) // Feminine Ordinal Sign ª alt+[
+#define BR_MORD LALT(BR_RBRC) // Masculine Ordinal Sign º alt+]
+#define BR_DGRE LALT(BR_SLSH) // Degree sign ° alt+/
+
+#define BR_EURO LALT(KC_E) // Euro sign € alt+e
+#define BR_NDTD LALT(BR_TILD) // Non-dead key tilde ~ alt+~
+#define BR_NDAC LALT(BR_ACUT) // Non-dead key acute accent ´ alt+´
+#define BR_NDGV LALT(BR_QUOT) // Non-dead key grave accent ` alt+'
+#define BR_NDCR LALT(BR_CIRC) // Non-dead key circumflex accent ^ alt+^ (alt+shift+~)
+#define BR_NDTR LALT(BR_TRMA) // Non-dead key trema accent ¨ alt+¨ (alt+shift+6)
+
+// For 101-key keyboard layouts, the ABNT2 layout allows
+// the slash and question mark to be typed using alt+q and alt+w.
+// The shortcuts are provided here for completeness' sake,
+// but it's recommended to use BR_SLSH and BR_QUES instead
+#define BR_ASLS LALT(KC_Q)
+#define BR_AQST LALT(KC_W)
+
+#endif
diff --git a/quantum/keymap_extras/keymap_canadian_multilingual.h b/quantum/keymap_extras/keymap_canadian_multilingual.h
new file mode 100644
index 0000000000..0bc20c7b9c
--- /dev/null
+++ b/quantum/keymap_extras/keymap_canadian_multilingual.h
@@ -0,0 +1,255 @@
+#ifndef KEYMAP_CANADIAN_MULTILINGUAG_H
+#define KEYMAP_CANADIAN_MULTILINGUAG_H
+
+#include "keymap.h"
+
+// Alt gr
+#ifndef ALTGR
+#define ALTGR(kc) RALT(kc)
+#endif
+#ifndef ALGR
+#define ALGR(kc) ALTGR(kc)
+#endif
+
+#define CSA_ALTGR KC_RALT
+#define CSA_ALGR CSA_ALTGR
+
+#ifndef GR2A
+#define GR2A(kc) RCTL(kc)
+#endif
+
+// Normal characters
+// First row
+#define CSA_SLASH KC_GRV // /
+#define CSA_SLSH CSA_SLASH
+
+// Second row
+#define CSA_DEAD_CIRCUMFLEX KC_LBRACKET // dead ^
+#define CSA_DCRC CSA_DEAD_CIRCUMFLEX
+#define CSA_C_CEDILLA KC_RBRACKET // Ç
+#define CSA_CCED CSA_C_CEDILLA
+
+// Third row
+#define CSA_E_GRAVE KC_QUOT // è
+#define CSA_EGRV CSA_E_GRAVE
+#define CSA_A_GRAVE KC_BSLASH // à
+#define CSA_AGRV CSA_A_GRAVE
+
+// Fourth row
+#define CSA_U_GRAVE KC_NONUS_BSLASH // ù
+#define CSA_UGRV CSA_U_GRAVE
+#define CSA_E_ACUTE KC_SLSH // é
+#define CSA_ECUT CSA_E_ACUTE
+
+// Shifted characters
+// First row
+#define CSA_BACKSLASH LSFT(CSA_SLASH) /* \ */
+#define CSA_BSLS CSA_BACKSLASH
+#define CSA_QUESTION LSFT(KC_6) // ?
+#define CSA_QEST CSA_QUESTION
+
+// Second row
+#define CSA_DEAD_TREMA LSFT(CSA_DEAD_CIRCUMFLEX) // dead trema/umlaut/diaresis for ä ë ï ö ü
+#define CSA_DTRM CSA_DEAD_TREMA
+
+// Third row
+// all same as US-QWERTY, or capitalised character of the non-shifted key
+
+// Fourth row
+#define CSA_APOSTROPHE LSFT(KC_COMMA) // '
+#define CSA_APOS CSA_APOSTROPHE
+#define CSA_DOUBLE_QUOTE LSFT(KC_DOT) // "
+#define CSA_DQOT CSA_DOUBLE_QUOTE
+
+// Alt Gr-ed characters
+// First row
+#define CSA_PIPE ALTGR(CSA_SLASH) // |
+#define CSA_CURRENCY ALTGR(KC_4) // ¤
+#define CSA_CURR CSA_CURRENCY
+#define CSA_LEFT_CURLY_BRACE ALTGR(KC_7) // {
+#define CSA_LCBR CSA_LEFT_CURLY_BRACE
+#define CSA_RIGHT_CURLY_BRACE ALTGR(KC_8) // }
+#define CSA_RCBR CSA_RIGHT_CURLY_BRACE
+#define CSA_LBRACKET ALTGR(KC_9) // [
+#define CSA_LBRC CSA_LBRACKET
+#define CSA_RBRACKET ALTGR(KC_0) // ]
+#define CSA_RBRC CSA_RBRACKET
+#define CSA_NEGATION ALTGR(KC_EQUAL) // ¬
+#define CSA_NEGT CSA_NEGATION
+
+// Second row
+// euro symbol not available on Linux? (X.org)
+#define CSA_EURO ALTGR(KC_E) // €
+#define CSA_DEAD_GRAVE ALTGR(CSA_DEAD_CIRCUMFLEX)
+#define CSA_DGRV CSA_DEAD_GRAVE // dead `
+#define CSA_DEAD_TILDE ALTGR(CSA_C_CEDILLA) // ~
+#define CSA_DTLD CSA_DEAD_TILDE
<