summary refs log tree commit diff
path: root/quantum
diff options
context:
space:
mode:
authorStanley Lai <stanleylai.sg@gmail.com>2017-02-13 12:36:22 -0800
committerStanley Lai <stanleylai.sg@gmail.com>2017-02-13 12:36:22 -0800
commita8eba1bddaf55224939a86bfa4d8e1b53e1d82db (patch)
tree906568677ed027a807d5e9c0c1bc1c2ae001f0f6 /quantum
parent53ea854462c0b3b2c3c58a36b714ac02f773c74f (diff)
parentfd2925efbac0d7963f3d267dd5264f08a0a4e9dc (diff)
Merge remote-tracking branch 'refs/remotes/qmk/master'
Diffstat (limited to 'quantum')
-rw-r--r--quantum/api/api_sysex.c60
-rw-r--r--quantum/audio/voices.c107
-rw-r--r--quantum/audio/voices.h2
-rw-r--r--quantum/config_common.h8
-rw-r--r--quantum/fauxclicky.c68
-rw-r--r--quantum/fauxclicky.h99
-rw-r--r--quantum/keymap.h313
-rw-r--r--quantum/keymap_common.c23
-rw-r--r--quantum/keymap_extras/keymap_br_abnt2.h16
-rwxr-xr-xquantum/light_ws2812.c6
-rw-r--r--quantum/matrix.c14
-rw-r--r--quantum/process_keycode/process_combo.c134
-rw-r--r--quantum/process_keycode/process_combo.h43
-rw-r--r--quantum/process_keycode/process_music.c12
-rw-r--r--quantum/process_keycode/process_tap_dance.c7
-rw-r--r--quantum/process_keycode/process_tap_dance.h1
-rw-r--r--quantum/process_keycode/process_unicode.c54
-rw-r--r--quantum/quantum.c193
-rw-r--r--quantum/quantum.h5
-rw-r--r--quantum/quantum_keycodes.h351
-rw-r--r--quantum/rgblight.c51
-rw-r--r--quantum/rgblight.h14
-rw-r--r--quantum/template/config.h2
-rw-r--r--quantum/template/rules.mk1
-rw-r--r--quantum/visualizer/visualizer.c58
-rw-r--r--quantum/visualizer/visualizer.h9
26 files changed, 1230 insertions, 421 deletions
diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c
index a4a554e764..868f854b92 100644
--- a/quantum/api/api_sysex.c
+++ b/quantum/api/api_sysex.c
@@ -1,4 +1,6 @@
 #include "api_sysex.h"
+#include "sysex_tools.h"
+#include "print.h"
 
 void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length) {
     // SEND_STRING("\nTX: ");
@@ -6,24 +8,50 @@ void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes,
     //     send_byte(bytes[i]);
     //     SEND_STRING(" ");
     // }
-    uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2));
-    precode[0] = message_type;
-    precode[1] = data_type;
-    memcpy(precode + 2, bytes, length);
-    uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2)));
-    uint16_t encoded_length = sysex_encode(encoded, precode, length + 2);
-    uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5));
-    array[0] = 0xF0;
-    array[1] = 0x00;
-    array[2] = 0x00;
-    array[3] = 0x00;
-    array[encoded_length + 4] = 0xF7;
-    memcpy(array + 4, encoded, encoded_length);
-    midi_send_array(&midi_device, encoded_length + 5, array);
+    if (length > API_SYSEX_MAX_SIZE) {
+        xprintf("Sysex msg too big %d %d %d", message_type, data_type, length);
+        return;
+    }
+
+
+    // The buffer size required is calculated as the following
+    // API_SYSEX_MAX_SIZE is the maximum length
+    // In addition to that we have a two byte message header consisting of the message_type and data_type
+    // This has to be encoded with an additional overhead of one byte for every starting 7 bytes
+    // We just add one extra byte in case it's not divisible by 7
+    // Then we have an unencoded header consisting of 4 bytes
+    // Plus a one byte terminator
+    const unsigned message_header = 2;
+    const unsigned unencoded_message = API_SYSEX_MAX_SIZE + message_header;
+    const unsigned encoding_overhead = unencoded_message / 7 + 1;
+    const unsigned encoded_size = unencoded_message + encoding_overhead;
+    const unsigned unencoded_header = 4;
+    const unsigned terminator = 1;
+    const unsigned buffer_size = encoded_size + unencoded_header + terminator;
+    uint8_t buffer[encoded_size + unencoded_header + terminator];
+    // The unencoded header
+    buffer[0] = 0xF0;
+    buffer[1] = 0x00;
+    buffer[2] = 0x00;
+    buffer[3] = 0x00;
+
+    // We copy the message to the end of the array, this way we can do an inplace encoding, using the same
+    // buffer for both input and output
+    const unsigned message_size = length + message_header;
+    uint8_t* unencoded_start = buffer + buffer_size - message_size;
+    uint8_t* ptr = unencoded_start;
+    *(ptr++) = message_type;
+    *(ptr++) = data_type;
+    memcpy(ptr, bytes, length);
+
+    unsigned encoded_length = sysex_encode(buffer + unencoded_header, unencoded_start, message_size);
+    unsigned final_size = unencoded_header + encoded_length + terminator;
+    buffer[final_size - 1] = 0xF7;
+    midi_send_array(&midi_device, final_size, buffer);
 
     // SEND_STRING("\nTD: ");
     // for (uint8_t i = 0; i < encoded_length + 5; i++) {
-    //     send_byte(array[i]);
+    //     send_byte(buffer[i]);
     //     SEND_STRING(" ");
     // }
-}
\ No newline at end of file
+}
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
index 06ff275ba4..8326e91eaa 100644
--- a/quantum/audio/voices.c
+++ b/quantum/audio/voices.c
@@ -33,6 +33,8 @@ float voice_envelope(float frequency) {
             polyphony_rate = 0;
 	        break;
 
+    #ifdef AUDIO_VOICES
+
         case something:
             glissando = false;
             polyphony_rate = 0;
@@ -58,36 +60,87 @@ float voice_envelope(float frequency) {
         case drums:
             glissando = false;
             polyphony_rate = 0;
-                note_timbre = 0;
+                // switch (compensated_index) {
+                //     case 0 ... 10:
+                //         note_timbre = 0.5;
+                //         break;
+                //     case 11 ... 20:
+                //         note_timbre = 0.5 * (21 - compensated_index) / 10;
+                //         break;
+                //     default:
+                //         note_timbre = 0;
+                //         break;
+                // }
+                // frequency = (rand() % (int)(frequency * 1.2 - frequency)) + (frequency * 0.8);
+
+            if (frequency < 80.0) {
+
+            } else if (frequency < 160.0) {
+
+                // Bass drum: 60 - 100 Hz
+                frequency = (rand() % (int)(40)) + 60;
+                switch (envelope_index) {
+                    case 0 ... 10:
+                        note_timbre = 0.5;
+                        break;
+                    case 11 ... 20:
+                        note_timbre = 0.5 * (21 - envelope_index) / 10;
+                        break;
+                    default:
+                        note_timbre = 0;
+                        break;
+                }
+
+            } else if (frequency < 320.0) {
+
+
+                // Snare drum: 1 - 2 KHz
+                frequency = (rand() % (int)(1000)) + 1000;
+                switch (envelope_index) {
+                    case 0 ... 5:
+                        note_timbre = 0.5;
+                        break;
+                    case 6 ... 20:
+                        note_timbre = 0.5 * (21 - envelope_index) / 15;
+                        break;
+                    default:
+                        note_timbre = 0;
+                        break;
+                }
+
+            } else if (frequency < 640.0) {
+
+                // Closed Hi-hat: 3 - 5 KHz
+                frequency = (rand() % (int)(2000)) + 3000;
+                switch (envelope_index) {
+                    case 0 ... 15:
+                        note_timbre = 0.5;
+                        break;
+                    case 16 ... 20:
+                        note_timbre = 0.5 * (21 - envelope_index) / 5;
+                        break;
+                    default:
+                        note_timbre = 0;
+                        break;
+                }
+
+            } else if (frequency < 1280.0) {
+
+                // Open Hi-hat: 3 - 5 KHz
+                frequency = (rand() % (int)(2000)) + 3000;
                 switch (envelope_index) {
-                    case 0 ... 20:
+                    case 0 ... 35:
                         note_timbre = 0.5;
+                        break;
+                    case 36 ... 50:
+                        note_timbre = 0.5 * (51 - envelope_index) / 15;
+                        break;
                     default:
-                        frequency = (rand() % (int)(frequency * 1.2 - frequency)) + (frequency * 0.8);
+                        note_timbre = 0;
                         break;
                 }
-            // if (frequency < 80.0) {
-            //     switch (envelope_index % 4) {
-            //         case 0:
-            //             frequency = 348.0;
-            //         case 1:
-            //             frequency = 53.0;
-            //         case 2:
-            //             frequency = 128.0;
-            //         case 3:
-            //             frequency = 934.0;
-            //         default:
-            //             break;
-            //     }
-            // } else if (frequency < 160.0) {
-
-            // } else if (frequency < 320.0) {
-
-            // } else if (frequency < 640.0) {
-
-            // } else if (frequency < 1280.0) {
-
-            // }
+
+            }
             break;
         case butts_fader:
             glissando = true;
@@ -217,11 +270,11 @@ float voice_envelope(float frequency) {
         //         note_timbre = 0.25;
         //     break;
 
+    #endif
+
 		default:
    			break;
     }
 
     return frequency;
 }
-
-
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h
index 72f139e9cd..52f7e006d6 100644
--- a/quantum/audio/voices.h
+++ b/quantum/audio/voices.h
@@ -11,6 +11,7 @@ float voice_envelope(float frequency);
 
 typedef enum {
     default_voice,
+    #ifdef AUDIO_VOICES
     something,
     drums,
     butts_fader,
@@ -23,6 +24,7 @@ typedef enum {
     // duty_fourth_down,
     // duty_third_down,
     // duty_fifth_third_down,
+    #endif
     number_of_voices // important that this is last
 } voice_type;
 
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 17c11faeb6..28f68b9c70 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -2,8 +2,10 @@
 #define CONFIG_DEFINITIONS_H
 
 /* diode directions */
-#define COL2ROW 0
-#define ROW2COL 1
+#define COL2ROW       0
+#define ROW2COL       1
+#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */
+
 /* I/O pins */
 #ifndef F0
     #define B0 0x30
@@ -80,4 +82,6 @@
 #   endif
 #endif
 
+#define API_SYSEX_MAX_SIZE 32
+
 #endif
diff --git a/quantum/fauxclicky.c b/quantum/fauxclicky.c
new file mode 100644
index 0000000000..13273e7058
--- /dev/null
+++ b/quantum/fauxclicky.c
@@ -0,0 +1,68 @@
+/*
+Copyright 2017 Priyadi Iman Nurcahyo
+
+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 <avr/interrupt.h>
+#include <avr/io.h>
+#include <timer.h>
+#include <fauxclicky.h>
+#include <stdbool.h>
+#include <musical_notes.h>
+
+__attribute__ ((weak))
+float fauxclicky_pressed_note[2] = MUSICAL_NOTE(_F3, 2);
+__attribute__ ((weak))
+float fauxclicky_released_note[2] = MUSICAL_NOTE(_A3, 2);
+__attribute__ ((weak))
+float fauxclicky_beep_note[2] = MUSICAL_NOTE(_C3, 2);
+
+bool fauxclicky_enabled = true;
+uint16_t note_start = 0;
+bool note_playing = false;
+uint16_t note_period = 0;
+
+void fauxclicky_init()
+{
+    // Set port PC6 (OC3A and /OC4A) as output
+    DDRC |= _BV(PORTC6);
+
+    // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
+    TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
+    TCCR3B = (1 << WGM33)  | (1 << WGM32)  | (0 << CS32)  | (1 << CS31) | (0 << CS30);
+}
+
+void fauxclicky_stop()
+{
+    FAUXCLICKY_DISABLE_OUTPUT;
+    note_playing = false;
+}
+
+void fauxclicky_play(float note[2]) {
+    if (!fauxclicky_enabled) return;
+    if (note_playing) fauxclicky_stop();
+    FAUXCLICKY_TIMER_PERIOD = (uint16_t)(((float)F_CPU) / (note[0] * FAUXCLICKY_CPU_PRESCALER));
+    FAUXCLICKY_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (note[0] * FAUXCLICKY_CPU_PRESCALER)) / 2);
+    note_playing = true;
+    note_period = (note[1] / 16) * (60 / (float)FAUXCLICKY_TEMPO) * 100;   // check this
+    note_start = timer_read();
+    FAUXCLICKY_ENABLE_OUTPUT;
+}
+
+void fauxclicky_check() {
+    if (!note_playing) return;
+
+    if (timer_elapsed(note_start) > note_period) {
+        fauxclicky_stop();
+    }
+}
diff --git a/quantum/fauxclicky.h b/quantum/fauxclicky.h
new file mode 100644
index 0000000000..109bd0d83e
--- /dev/null
+++ b/quantum/fauxclicky.h
@@ -0,0 +1,99 @@
+/*
+Copyright 2017 Priyadi Iman Nurcahyo
+
+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/>.
+*/
+
+#ifdef AUDIO_ENABLE
+#error "AUDIO_ENABLE and FAUXCLICKY_ENABLE cannot be both enabled"
+#endif
+
+#include "musical_notes.h"
+#include "stdbool.h"
+
+__attribute__ ((weak))
+float fauxclicky_pressed_note[2];
+__attribute__ ((weak))
+float fauxclicky_released_note[2];
+__attribute__ ((weak))
+float fauxclicky_beep_note[2];
+
+bool fauxclicky_enabled;
+
+//
+// tempo in BPM
+//
+
+#ifndef FAUXCLICKY_TEMPO
+#define FAUXCLICKY_TEMPO TEMPO_DEFAULT
+#endif
+
+// beep on press
+#define FAUXCLICKY_ACTION_PRESS fauxclicky_play(fauxclicky_pressed_note)
+
+// beep on release
+#define FAUXCLICKY_ACTION_RELEASE fauxclicky_play(fauxclicky_released_note)
+
+// general purpose beep
+#define FAUXCLICKY_BEEP fauxclicky_play(fauxclicky_beep_note)
+
+// enable
+#define FAUXCLICKY_ON fauxclicky_enabled = true
+
+// disable
+#define FAUXCLICKY_OFF do { \
+    fauxclicky_enabled = false; \
+    fauxclicky_stop(); \
+} while (0)
+
+// toggle
+#define FAUXCLICKY_TOGGLE do { \
+    if (fauxclicky_enabled) { \
+        FAUXCLICKY_OFF; \
+    } else { \
+        FAUXCLICKY_ON; \
+    } \
+} while (0)
+
+//
+// pin configuration
+//
+
+#ifndef FAUXCLICKY_CPU_PRESCALER
+#define FAUXCLICKY_CPU_PRESCALER 8
+#endif
+
+#ifndef FAUXCLICKY_ENABLE_OUTPUT
+#define FAUXCLICKY_ENABLE_OUTPUT TCCR3A |= _BV(COM3A1);
+#endif
+
+#ifndef FAUXCLICKY_DISABLE_OUTPUT
+#define FAUXCLICKY_DISABLE_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
+#endif
+
+#ifndef FAUXCLICKY_TIMER_PERIOD
+#define FAUXCLICKY_TIMER_PERIOD ICR3
+#endif
+
+#ifndef FAUXCLICKY_DUTY_CYCLE
+#define FAUXCLICKY_DUTY_CYCLE OCR3A
+#endif
+
+//
+// definitions
+//
+
+void fauxclicky_init(void);
+void fauxclicky_stop(void);
+void fauxclicky_play(float note[2]);
+void fauxclicky_check(void);
+
diff --git a/quantum/keymap.h b/quantum/keymap.h
index ae56d16c75..c000d2da8e 100644
--- a/quantum/keymap.h
+++ b/quantum/keymap.h
@@ -38,317 +38,16 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define RESET QK_RESET
 #endif
 
-/* translates key to keycode */
+#include "quantum_keycodes.h"
+
+// translates key to keycode
 uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
 
+// translates function id to action
+uint16_t keymap_function_id_to_action( uint16_t function_id );
+
 extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
 extern const uint16_t fn_actions[];
 
-enum quantum_keycodes {
-    // Ranges used in shortucuts - not to be used directly
-    QK_TMK                = 0x0000,
-    QK_TMK_MAX            = 0x00FF,
-    QK_MODS               = 0x0100,
-    QK_LCTL               = 0x0100,
-    QK_LSFT               = 0x0200,
-    QK_LALT               = 0x0400,
-    QK_LGUI               = 0x0800,
-    QK_RCTL               = 0x1100,
-    QK_RSFT               = 0x1200,
-    QK_RALT               = 0x1400,
-    QK_RGUI               = 0x1800,
-    QK_MODS_MAX           = 0x1FFF,
-    QK_FUNCTION           = 0x2000,
-    QK_FUNCTION_MAX       = 0x2FFF,
-    QK_MACRO              = 0x3000,
-    QK_MACRO_MAX          = 0x3FFF,
-    QK_LAYER_TAP          = 0x4000,
-    QK_LAYER_TAP_MAX      = 0x4FFF,
-    QK_TO                 = 0x5000,
-    QK_TO_MAX             = 0x50FF,
-    QK_MOMENTARY          = 0x5100,
-    QK_MOMENTARY_MAX      = 0x51FF,
-    QK_DEF_LAYER          = 0x5200,
-    QK_DEF_LAYER_MAX      = 0x52FF,
-    QK_TOGGLE_LAYER       = 0x5300,
-    QK_TOGGLE_LAYER_MAX   = 0x53FF,
-    QK_ONE_SHOT_LAYER     = 0x5400,
-    QK_ONE_SHOT_LAYER_MAX = 0x54FF,
-    QK_ONE_SHOT_MOD       = 0x5500,
-    QK_ONE_SHOT_MOD_MAX   = 0x55FF,
-#ifndef DISABLE_CHORDING
-    QK_CHORDING           = 0x5600,
-    QK_CHORDING_MAX       = 0x56FF,
-#endif
-    QK_MOD_TAP            = 0x6000,
-    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,
-#endif
-
-    // Loose keycodes - to be used directly
-
-    RESET = 0x7000,
-    DEBUG,
-    MAGIC_SWAP_CONTROL_CAPSLOCK,
-    MAGIC_CAPSLOCK_TO_CONTROL,
-    MAGIC_SWAP_LALT_LGUI,
-    MAGIC_SWAP_RALT_RGUI,
-    MAGIC_NO_GUI,
-    MAGIC_SWAP_GRAVE_ESC,
-    MAGIC_SWAP_BACKSLASH_BACKSPACE,
-    MAGIC_HOST_NKRO,
-    MAGIC_SWAP_ALT_GUI,
-    MAGIC_UNSWAP_CONTROL_CAPSLOCK,
-    MAGIC_UNCAPSLOCK_TO_CONTROL,
-    MAGIC_UNSWAP_LALT_LGUI,
-    MAGIC_UNSWAP_RALT_RGUI,
-    MAGIC_UNNO_GUI,
-    MAGIC_UNSWAP_GRAVE_ESC,
-    MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
-    MAGIC_UNHOST_NKRO,
-    MAGIC_UNSWAP_ALT_GUI,
-    MAGIC_TOGGLE_NKRO,
-
-    // Leader key
-#ifndef DISABLE_LEADER
-    KC_LEAD,
-#endif
-
-    // Audio on/off/toggle
-    AU_ON,
-    AU_OFF,
-    AU_TOG,
-
-    // Music mode on/off/toggle
-    MU_ON,
-    MU_OFF,
-    MU_TOG,
-
-    // Music voice iterate
-    MUV_IN,
-    MUV_DE,
-
-    // Midi mode on/off
-    MIDI_ON,
-    MIDI_OFF,
-
-    // Backlight functionality
-    BL_0,
-    BL_1,
-    BL_2,
-    BL_3,
-    BL_4,
-    BL_5,
-    BL_6,
-    BL_7,
-    BL_8,
-    BL_9,
-    BL_10,
-    BL_11,
-    BL_12,
-    BL_13,
-    BL_14,
-    BL_15,
-    BL_DEC,
-    BL_INC,
-    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,
-
-    // Right shift, close paren
-    KC_RSPC,
-
-    // Printing
-    PRINT_ON,
-    PRINT_OFF,
-
-    // always leave at the end
-    SAFE_RANGE
-};
-
-// Ability to use mods in layouts
-#define LCTL(kc) (kc | QK_LCTL)
-#define LSFT(kc) (kc | QK_LSFT)
-#define LALT(kc) (kc | QK_LALT)
-#define LGUI(kc) (kc | QK_LGUI)
-#define RCTL(kc) (kc | QK_RCTL)
-#define RSFT(kc) (kc | QK_RSFT)
-#define RALT(kc) (kc | QK_RALT)
-#define RGUI(kc) (kc | QK_RGUI)
-
-#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
-
-
-// Aliases for shifted symbols
-// Each key has a 4-letter code, and some have longer aliases too.
-// While the long aliases are descriptive, the 4-letter codes
-// make for nicer grid layouts (everything lines up), and are
-// the preferred style for Quantum.
-#define KC_TILD LSFT(KC_GRV)    // ~
-#define KC_TILDE    KC_TILD
-
-#define KC_EXLM LSFT(KC_1)      // !
-#define KC_EXCLAIM  KC_EXLM
-
-#define KC_AT   LSFT(KC_2)      // @
-
-#define KC_HASH LSFT(KC_3)      // #
-
-#define KC_DLR  LSFT(KC_4)      // $
-#define KC_DOLLAR   KC_DLR
-
-#define KC_PERC LSFT(KC_5)      // %
-#define KC_PERCENT  KC_PERC
-
-#define KC_CIRC LSFT(KC_6)      // ^
-#define KC_CIRCUMFLEX   KC_CIRC
-
-#define KC_AMPR LSFT(KC_7)      // &
-#define KC_AMPERSAND    KC_AMPR
-
-#define KC_ASTR LSFT(KC_8)      // *
-#define KC_ASTERISK KC_ASTR
-
-#define KC_LPRN LSFT(KC_9)      // (
-#define KC_LEFT_PAREN   KC_LPRN
-
-#define KC_RPRN LSFT(KC_0)      // )
-#define KC_RIGHT_PAREN  KC_RPRN
-
-#define KC_UNDS LSFT(KC_MINS)   // _
-#define KC_UNDERSCORE   KC_UNDS
-
-#define KC_PLUS LSFT(KC_EQL)    // +
-
-#define KC_LCBR LSFT(KC_LBRC)   // {
-#define KC_LEFT_CURLY_BRACE KC_LCBR
-
-#define KC_RCBR LSFT(KC_RBRC)   // }
-#define KC_RIGHT_CURLY_BRACE    KC_RCBR
-
-#define KC_LABK LSFT(KC_COMM)   // <
-#define KC_LEFT_ANGLE_BRACKET   KC_LABK
-
-#define KC_RABK LSFT(KC_DOT)    // >
-#define KC_RIGHT_ANGLE_BRACKET  KC_RABK
-
-#define KC_COLN LSFT(KC_SCLN)   // :
-#define KC_COLON    KC_COLN
-
-#define KC_PIPE LSFT(KC_BSLS)   // |
-
-#define KC_LT LSFT(KC_COMM)     // <
-
-#define KC_GT LSFT(KC_DOT)      // >
-
-#define KC_QUES LSFT(KC_SLSH)   // ?
-#define KC_QUESTION KC_QUES
-
-#define KC_DQT LSFT(KC_QUOT)   // "
-#define KC_DOUBLE_QUOTE KC_DQT
-#define KC_DQUO KC_DQT
-
-#define KC_DELT KC_DELETE // Del key (four letter code)
-
-// Alias for function layers than expand past FN31
-#define FUNC(kc) (kc | QK_FUNCTION)
-
-// Aliases
-#define S(kc) LSFT(kc)
-#define F(kc) FUNC(kc)
-
-#define M(kc) (kc | QK_MACRO)
-
-#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
-
-// L-ayer, T-ap - 256 keycode max, 16 layer max
-#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
-
-#define AG_SWAP MAGIC_SWAP_ALT_GUI
-#define AG_NORM MAGIC_UNSWAP_ALT_GUI
-
-#define BL_ON  BL_9
-#define BL_OFF BL_0
-
-#define MI_ON MIDI_ON
-#define MI_OFF MIDI_OFF
-
-// GOTO layer - 16 layers max
-// when:
-// ON_PRESS    = 1
-// ON_RELEASE  = 2
-// Unless you have a good reason not to do so, prefer  ON_PRESS (1) as your default.
-// 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)
-
-// Set default layer - 256 layer max
-#define DF(layer) (layer | QK_DEF_LAYER)
-
-// Toggle to layer - 256 layer max
-#define TG(layer) (layer | QK_TOGGLE_LAYER)
-
-// One-shot layer - 256 layer max
-#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
-
-// 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))
-#define CTL_T(kc) MT(MOD_LCTL, kc)
-#define SFT_T(kc) MT(MOD_LSFT, kc)
-#define ALT_T(kc) MT(MOD_LALT, kc)
-#define GUI_T(kc) MT(MOD_LGUI, kc)
-#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
-#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
-#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui
-#define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
-
-// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
-#define KC_HYPR HYPR(KC_NO)
-#define KC_MEH  MEH(KC_NO)
-
-#ifdef UNICODE_ENABLE
-    // For sending unicode codes.
-    // You may not send codes over 7FFF -- this supports most of UTF8.
-    // To have a key that sends out Œ, go UC(0x0152)
-    #define UNICODE(n) (n | QK_UNICODE)
-    #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 833e5a8f8d..54b872d49e 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -48,12 +48,10 @@ action_t action_for_key(uint8_t layer, keypos_t key)
 
     action_t action;
     uint8_t action_layer, when, mod;
-    // The arm-none-eabi compiler generates out of bounds warnings when using the fn_actions directly for some reason
-    const uint16_t* actions = fn_actions;
 
     switch (keycode) {
         case KC_FN0 ... KC_FN31:
-            action.code = pgm_read_word(&actions[FN_INDEX(keycode)]);
+            action.code = keymap_function_id_to_action(FN_INDEX(keycode));
             break;
         case KC_A ... KC_EXSEL:
         case KC_LCTRL ... KC_RGUI:
@@ -79,10 +77,13 @@ action_t action_for_key(uint8_t layer, keypos_t key)
         case QK_FUNCTION ... QK_FUNCTION_MAX: ;
             // Is a shortcut for function action_layer, pull last 12bits
             // This means we have 4,096 FN macros at our disposal
-            action.code = pgm_read_word(&actions[(int)keycode & 0xFFF]);
+            action.code = keymap_function_id_to_action( (int)keycode & 0xFFF );
             break;
         case QK_MACRO ... QK_MACRO_MAX:
-            action.code = ACTION_MACRO(keycode & 0xFF);
+            if (keycode & 0x800) // tap macros have upper bit set
+                action.code = ACTION_MACRO_TAP(keycode & 0xFF);
+            else
+                action.code = ACTION_MACRO(keycode & 0xFF);
             break;
         case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
             action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
@@ -119,7 +120,7 @@ action_t action_for_key(uint8_t layer, keypos_t key)
             action.code = ACTION_MODS_ONESHOT(mod);
             break;
         case QK_MOD_TAP ... QK_MOD_TAP_MAX:
-            action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
+            action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0x1F, keycode & 0xFF);
             break;
     #ifdef BACKLIGHT_ENABLE
         case BL_0 ... BL_15:
@@ -163,9 +164,17 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
 {
 }
 
-/* translates key to 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)]);
 }
+
+// translates function id to action
+__attribute__ ((weak))
+uint16_t keymap_function_id_to_action( uint16_t function_id )
+{
+	return pgm_read_word(&fn_actions[function_id]);
+}
diff --git a/quantum/keymap_extras/keymap_br_abnt2.h b/quantum/keymap_extras/keymap_br_abnt2.h
index 0df177721d..b001139dd4 100644
--- a/quantum/keymap_extras/keymap_br_abnt2.h
+++ b/quantum/keymap_extras/keymap_br_abnt2.h
@@ -1,3 +1,19 @@
+/* Copyright 2017 Potiguar Faga
+ *
+ * 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/>.
+ */
+
 #ifndef KEYMAP_BR_ABNT2_H
 #define KEYMAP_BR_ABNT2_H
 
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c
index a883b13884..55bdd9cd81 100755
--- a/quantum/light_ws2812.c
+++ b/quantum/light_ws2812.c
@@ -70,7 +70,7 @@ void I2C_WriteBit(unsigned char c)
 
 // Inits bitbanging port, must be called before using the functions below
 //
-void I2C_Init()
+void I2C_Init(void)
 {
     I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
 
@@ -82,7 +82,7 @@ void I2C_Init()
 
 // Send a START Condition
 //
-void I2C_Start()
+void I2C_Start(void)
 {
     // set both to high at the same time
     I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
@@ -97,7 +97,7 @@ void I2C_Start()
 
 // Send a STOP Condition
 //
-void I2C_Stop()
+void I2C_Stop(void)
 {
     I2C_CLOCK_HI();
     _delay_us(I2C_DELAY);
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 07eb87bc36..ac523482ad 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -60,13 +60,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
     extern const matrix_row_t matrix_mask[];
 #endif
 
+#if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
 static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+#endif
 
 /* matrix state(1:on, 0:off) */
 static matrix_row_t matrix[MATRIX_ROWS];
 
-static matrix_row_t matrix_raw[MATRIX_ROWS];
 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
 
 
@@ -76,7 +77,7 @@ static matrix_row_t matrix_debouncing[MATRIX_ROWS];
     static void unselect_rows(void);
     static void select_row(uint8_t row);
     static void unselect_row(uint8_t row);
-#else // ROW2COL
+#elif (DIODE_DIRECTION == ROW2COL)
     static void init_rows(void);
     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
     static void unselect_cols(void);
@@ -133,7 +134,7 @@ uint8_t matrix_cols(void) {
 //         /* PORTxn */
 //         _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
 //     }
-// #else
+// #elif (DIODE_DIRECTION == ROW2COL)
 //     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
 //         /* DDRxn */
 //         _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
@@ -158,7 +159,7 @@ void matrix_init(void) {
 #if (DIODE_DIRECTION == COL2ROW)
     unselect_rows();
     init_cols();
-#else // ROW2COL
+#elif (DIODE_DIRECTION == ROW2COL)
     unselect_cols();
     init_rows();
 #endif
@@ -166,7 +167,6 @@ void matrix_init(void) {
     // initialize matrix state: all keys off
     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
         matrix[i] = 0;
-        matrix_raw[i] = 0;
         matrix_debouncing[i] = 0;
     }
 
@@ -194,7 +194,7 @@ uint8_t matrix_scan(void)
 
     }
 
-#else // ROW2COL
+#elif (DIODE_DIRECTION == ROW2COL)
 
     // Set col, read rows
     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
@@ -336,7 +336,7 @@ static void unselect_rows(void)
     }
 }
 
-#else // ROW2COL
+#elif (DIODE_DIRECTION == ROW2COL)
 
 static void init_rows(void)
 {
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
new file mode 100644
index 0000000000..e2189ad98b
--- /dev/null
+++ b/quantum/process_keycode/process_combo.c
@@ -0,0 +1,134 @@
+#include "process_combo.h"
+#include "print.h"
+
+
+#define COMBO_TIMER_ELAPSED -1
+
+
+__attribute__ ((weak))
+combo_t key_combos[] = {
+
+};
+
+__attribute__ ((weak))
+void process_combo_event(uint8_t combo_index, bool pressed) {
+
+}
+
+static uint8_t current_combo_index = 0;
+
+static inline void send_combo(uint16_t action, bool pressed)
+{
+    if (action) {
+        if (pressed) {
+            register_code16(action);
+        } else {
+            unregister_code16(action);
+        }
+    } else {
+        process_combo_event(current_combo_index, pressed);
+    }
+}
+
+#define ALL_COMBO_KEYS_ARE_DOWN     (((1<<count)-1) == combo->state)
+#define NO_COMBO_KEYS_ARE_DOWN      (0 == combo->state)
+#define KEY_STATE_DOWN(key)         do{ combo->state |= (1<<key); } while(0)
+#define KEY_STATE_UP(key)           do{ combo->state &= ~(1<<key); } while(0)
+static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record) 
+{
+    uint8_t count = 0;
+    uint8_t index = -1;
+    /* Find index of keycode and number of combo keys */
+    for (const uint16_t *keys = combo->keys; ;++count) {
+        uint16_t key = pgm_read_word(&keys[count]);
+        if (keycode == key) index = count;
+        if (COMBO_END == key) break;
+    }
+
+    /* Return if not a combo key */
+    if (-1 == (int8_t)index) return false;
+
+    /* The combos timer is used to signal whether the combo is active */
+    bool is_combo_active = COMBO_TIMER_ELAPSED == combo->timer ? false : true;
+
+    if (record->event.pressed) {
+        KEY_STATE_DOWN(index);
+
+        if (is_combo_active) {
+            if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was pressed */
+                send_combo(combo->keycode, true);
+                combo->timer = COMBO_TIMER_ELAPSED;
+            } else { /* Combo key was pressed */
+                combo->timer = timer_read();
+#ifdef COMBO_ALLOW_ACTION_KEYS
+                combo->prev_record = *record;
+#else
+                combo->prev_key = keycode;
+#endif
+            }
+        }
+    } else {
+        if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was released */
+            send_combo(combo->keycode, false);
+        }
+
+        if (is_combo_active) { /* Combo key was tapped */
+#ifdef COMBO_ALLOW_ACTION_KEYS
+            record->event.pressed = true;
+            process_action(record, store_or_get_action(record->event.pressed, record->event.key));
+            record->event.pressed = false;
+            process_action(record, store_or_get_action(record->event.pressed, record->event.key));
+#else
+            register_code16(keycode);
+            send_keyboard_report();
+            unregister_code16(keycode);
+#endif
+            combo->timer = 0;            
+        }
+
+        KEY_STATE_UP(index);        
+    }
+
+    if (NO_COMBO_KEYS_ARE_DOWN) {
+        combo->timer = 0;
+    }
+
+    return is_combo_active;
+}
+
+bool process_combo(uint16_t keycode, keyrecord_t *record)
+{
+    bool is_combo_key = false;
+
+    for (current_combo_index = 0; current_combo_index < COMBO_COUNT; ++current_combo_index) {
+        combo_t *combo = &key_combos[current_combo_index];
+        is_combo_key |= process_single_combo(combo, keycode, record);
+    }    
+
+    return !is_combo_key;
+}
+
+void matrix_scan_combo(void)
+{
+    for (int i = 0; i < COMBO_COUNT; ++i) {
+        combo_t *combo = &key_combos[i];
+        if (combo->timer && 
+            combo->timer != COMBO_TIMER_ELAPSED && 
+            timer_elapsed(combo->timer) > COMBO_TERM) {
+            
+            /* This disables the combo, meaning key events for this
+             * combo will be handled by the next processors in the chain 
+             */
+            combo->timer = COMBO_TIMER_ELAPSED;
+
+#ifdef COMBO_ALLOW_ACTION_KEYS
+            process_action(&combo->prev_record, 
+                store_or_get_action(combo->prev_record.event.pressed, 
+                                    combo->prev_record.event.key));
+#else
+            unregister_code16(combo->prev_key);
+            register_code16(combo->prev_key);
+#endif
+        }
+    }
+}
diff --git a/quantum/process_keycode/process_combo.h b/quantum/process_keycode/process_combo.h
new file mode 100644
index 0000000000..847f2b7376
--- /dev/null
+++ b/quantum/process_keycode/process_combo.h
@@ -0,0 +1,43 @@
+#ifndef PROCESS_COMBO_H
+#define PROCESS_COMBO_H
+
+#include <stdint.h>
+#include "progmem.h"
+#include "quantum.h"
+
+typedef struct
+{
+    const uint16_t *keys;
+    uint16_t keycode;        
+#ifdef EXTRA_EXTRA_LONG_COMBOS
+    uint32_t state;
+#elif EXTRA_LONG_COMBOS
+    uint16_t state;
+#else
+    uint8_t state;
+#endif
+    uint16_t timer;
+#ifdef COMBO_ALLOW_ACTION_KEYS
+    keyrecord_t prev_record;
+#else
+    uint16_t prev_key;
+#endif
+} combo_t;
+
+
+#define COMBO(ck, ca)       {.keys = &(ck)[0], .keycode = (ca)}
+#define COMBO_ACTION(ck)    {.keys = &(ck)[0]}
+
+#define COMBO_END 0
+#ifndef COMBO_COUNT
+#define COMBO_COUNT 0
+#endif
+#ifndef COMBO_TERM
+#define COMBO_TERM TAPPING_TERM
+#endif
+
+bool process_combo(uint16_t keycode, keyrecord_t *record);
+void matrix_scan_combo(void);
+void process_combo_event(uint8_t combo_index, bool pressed);
+
+#endif
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c
index bae43943e0..1e2648bff5 100644
--- a/quantum/process_keycode/process_music.c
+++ b/quantum/process_keycode/process_music.c
@@ -114,8 +114,18 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
             music_sequence_interval+=10;
         return false;
       }
-
+      #define MUSIC_MODE_GUITAR
+
+      #ifdef MUSIC_MODE_CHROMATIC
+      float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(music_starting_note + record->event.key.col + music_offset)/12.0+(MATRIX_ROWS - record->event.key.row));
+      #elif defined(MUSIC_MODE_GUITAR)
+      float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(music_starting_note + record->event.key.col + music_offset)/12.0+(float)(MATRIX_ROWS - record->event.key.row + 7)*5.0/12);
+      #elif defined(MUSIC_MODE_VIOLIN)
+      float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(music_starting_note + record->event.key.col + music_offset)/12.0+(float)(MATRIX_ROWS - record->event.key.row + 5)*7.0/12);
+      #else
       float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(music_starting_note + SCALE[record->event.key.col + music_offset])/12.0+(MATRIX_ROWS - record->event.key.row));
+      #endif
+
       if (record->event.pressed) {
         play_note(freq, 0xF);
         if (music_sequence_recording) {
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 6ae362c4c2..403dca5380 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -43,12 +43,16 @@ static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_acti
   if (action->state.finished)
     return;
   action->state.finished = true;
+  add_mods(action->state.oneshot_mods);
+  send_keyboard_report();
   _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished);
 }
 
 static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action)
 {
   _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset);
+  del_mods(action->state.oneshot_mods);
+  send_keyboard_report();
 }
 
 bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
@@ -70,6 +74,7 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
       action->state.keycode = keycode;
       action->state.count++;
       action->state.timer = timer_read();
+      action->state.oneshot_mods = get_oneshot_mods();
       process_tap_dance_action_on_each_tap (action);
 
       if (last_td && last_td != keycode) {
@@ -109,7 +114,7 @@ void matrix_scan_tap_dance () {
   if (highest_td == -1)
     return;
 
-  for (int i = 0; i <= highest_td; i++) {
+for (int i = 0; i <= highest_td; i++) {
     qk_tap_dance_action_t *action = &tap_dance_actions[i];
 
     if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) {
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index f753cbba66..726752ecc7 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -9,6 +9,7 @@
 typedef struct
 {
   uint8_t count;
+  uint8_t oneshot_mods;
   uint16_t keycode;
   uint16_t timer;
   bool interrupted;
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
index cd3a610b4d..9d01a592d2 100644
--- a/quantum/process_keycode/process_unicode.c
+++ b/quantum/process_keycode/process_unicode.c
@@ -1,6 +1,8 @@
 #include "process_unicode.h"
+#include "action_util.h"
 
 static uint8_t input_mode;
+uint8_t mods;
 
 __attribute__((weak))
 uint16_t hex_to_keycode(uint8_t hex)
@@ -25,6 +27,19 @@ uint8_t get_unicode_input_mode(void) {
 
 __attribute__((weak))
 void unicode_input_start (void) {
+  // save current mods
+  mods = keyboard_report->mods;
+
+  // unregister all mods to start from clean state
+  if (mods & MOD_BIT(KC_LSFT)) unregister_code(KC_LSFT);
+  if (mods & MOD_BIT(KC_RSFT)) unregister_code(KC_RSFT);
+  if (mods & MOD_BIT(KC_LCTL)) unregister_code(KC_LCTL);
+  if (mods & MOD_BIT(KC_RCTL)) unregister_code(KC_RCTL);
+  if (mods & MOD_BIT(KC_LALT)) unregister_code(KC_LALT);
+  if (mods & MOD_BIT(KC_RALT)) unregister_code(KC_RALT);
+  if (mods & MOD_BIT(KC_LGUI)) unregister_code(KC_LGUI);
+  if (mods & MOD_BIT(KC_RGUI)) unregister_code(KC_RGUI);
+
   switch(input_mode) {
   case UC_OSX:
     register_code(KC_LALT);
@@ -54,15 +69,25 @@ void unicode_input_start (void) {
 __attribute__((weak))
 void unicode_input_finish (void) {
   switch(input_mode) {
-  case UC_OSX:
-  case UC_WIN:
-    unregister_code(KC_LALT);
-    break;
-  case UC_LNX:
-    register_code(KC_SPC);
-    unregister_code(KC_SPC);
-    break;
+    case UC_OSX:
+    case UC_WIN:
+      unregister_code(KC_LALT);
+      break;
+    case UC_LNX:
+      register_code(KC_SPC);
+      unregister_code(KC_SPC);
+      break;
   }
+
+  // reregister previously set mods
+  if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT);
+  if (mods & MOD_BIT(KC_RSFT)) register_code(KC_RSFT);
+  if (mods & MOD_BIT(KC_LCTL)) register_code(KC_LCTL);
+  if (mods & MOD_BIT(KC_RCTL)) register_code(KC_RCTL);
+  if (mods & MOD_BIT(KC_LALT)) register_code(KC_LALT);
+  if (mods & MOD_BIT(KC_RALT)) register_code(KC_RALT);
+  if (mods & MOD_BIT(KC_LGUI)) register_code(KC_LGUI);
+  if (mods & MOD_BIT(KC_RGUI)) register_code(KC_RGUI);
 }
 
 void register_hex(uint16_t hex) {
@@ -114,9 +139,18 @@ void unicode_map_input_error() {}
 bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
   if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) {
     const uint32_t* map = unicode_map;
-    uint16_t index = keycode & 0x7FF;
+    uint16_t index = keycode - QK_UNICODE_MAP;
     uint32_t code = pgm_read_dword_far(&map[index]);
-    if ((code > 0xFFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
+    if (code > 0xFFFF && code <= 0x10ffff && input_mode == UC_OSX) {
+      // Convert to UTF-16 surrogate pair
+      code -= 0x10000;
+      uint32_t lo = code & 0x3ff;
+      uint32_t hi = (code & 0xffc00) >> 10;
+      unicode_input_start();
+      register_hex32(hi + 0xd800);
+      register_hex32(lo + 0xdc00);
+      unicode_input_finish();
+    } else if ((code > 0x10ffff && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
       // when character is out of range supported by the OS
       unicode_map_input_error();
     } else {
diff --git a/quantum/quantum.c b/quantum/quantum.c
index f653564a67..2088c10c95 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -1,9 +1,16 @@
 #include "quantum.h"
+#ifdef PROTOCOL_LUFA
+#include "outputselect.h"
+#endif
 
 #ifndef TAPPING_TERM
 #define TAPPING_TERM 200
 #endif
 
+#ifdef FAUXCLICKY_ENABLE
+#include "fauxclicky.h"
+#endif
+
 static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
   switch (code) {
   case QK_MODS ... QK_MODS_MAX:
@@ -21,6 +28,8 @@ static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
   if (code & QK_LGUI)
     f(KC_LGUI);
 
+  if (code < QK_RMODS_MIN) return;
+
   if (code & QK_RCTL)
     f(KC_RCTL);
   if (code & QK_RSFT)
@@ -31,14 +40,42 @@ static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
     f(KC_RGUI);
 }
 
+static inline void qk_register_weak_mods(uint8_t kc) {
+    add_weak_mods(MOD_BIT(kc));
+    send_keyboard_report();
+}
+
+static inline void qk_unregister_weak_mods(uint8_t kc) {
+    del_weak_mods(MOD_BIT(kc));
+    send_keyboard_report();
+}
+
+static inline void qk_register_mods(uint8_t kc) {
+    add_weak_mods(MOD_BIT(kc));
+    send_keyboard_report();
+}
+
+static inline void qk_unregister_mods(uint8_t kc) {
+    del_weak_mods(MOD_BIT(kc));
+    send_keyboard_report();
+}
+
 void register_code16 (uint16_t code) {
-  do_code16 (code, register_code);
+  if (IS_MOD(code) || code == KC_NO) {
+      do_code16 (code, qk_register_mods);
+  } else {
+      do_code16 (code, qk_register_weak_mods);
+  }
   register_code (code);
 }
 
 void unregister_code16 (uint16_t code) {
   unregister_code (code);
-  do_code16 (code, unregister_code);
+  if (IS_MOD(code) || code == KC_NO) {
+      do_code16 (code, qk_unregister_mods);
+  } else {
+      do_code16 (code, qk_unregister_weak_mods);
+  }
 }
 
 __attribute__ ((weak))
@@ -128,6 +165,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #ifndef DISABLE_CHORDING
     process_chording(keycode, record) &&
   #endif
+  #ifdef COMBO_ENABLE
+    process_combo(keycode, record) &&
+  #endif
   #ifdef UNICODE_ENABLE
     process_unicode(keycode, record) &&
   #endif
@@ -160,6 +200,26 @@ bool process_record_quantum(keyrecord_t *record) {
       }
 	  return false;
       break;
+  #ifdef FAUXCLICKY_ENABLE
+  case FC_TOG:
+    if (record->event.pressed) {
+      FAUXCLICKY_TOGGLE;
+    }
+    return false;
+    break;
+  case FC_ON:
+    if (record->event.pressed) {
+      FAUXCLICKY_ON;
+    }
+    return false;
+    break;
+  case FC_OFF:
+    if (record->event.pressed) {
+      FAUXCLICKY_OFF;
+    }
+    return false;
+    break;
+  #endif
 	#ifdef RGBLIGHT_ENABLE
 	case RGB_TOG:
 		if (record->event.pressed) {
@@ -210,6 +270,36 @@ bool process_record_quantum(keyrecord_t *record) {
 	  return false;
       break;
 	#endif
+    #ifdef PROTOCOL_LUFA
+    case OUT_AUTO:
+      if (record->event.pressed) {
+        set_output(OUTPUT_AUTO);
+      }
+      return false;
+      break;
+    case OUT_USB:
+      if (record->event.pressed) {
+        set_output(OUTPUT_USB);
+      }
+      return false;
+      break;
+    #ifdef BLUETOOTH_ENABLE
+    case OUT_BT:
+      if (record->event.pressed) {
+        set_output(OUTPUT_BLUETOOTH);
+      }
+      return false;
+      break;
+    #endif
+    #ifdef ADAFRUIT_BLE_ENABLE
+    case OUT_BLE:
+      if (record->event.pressed) {
+        set_output(OUTPUT_ADAFRUIT_BLE);
+      }
+      return false;
+      break;
+    #endif
+    #endif
     case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO:
       if (record->event.pressed) {
         // MAGIC actions (BOOTMAGIC without the boot)
@@ -506,6 +596,11 @@ void matrix_scan_quantum() {
   #ifdef TAP_DANCE_ENABLE
     matrix_scan_tap_dance();
   #endif
+
+  #ifdef COMBO_ENABLE
+    matrix_scan_combo();
+  #endif
+
   matrix_scan_kb();
 }
 
@@ -523,34 +618,45 @@ static const uint8_t backlight_pin = BACKLIGHT_PIN;
 #  define COM1x1 COM1A1
 #  define OCR1x  OCR1A
 #else
-#  error "Backlight pin not supported - use B5, B6, or B7"
+#  define NO_BACKLIGHT_CLOCK
+#endif
+
+#ifndef BACKLIGHT_ON_STATE
+#define BACKLIGHT_ON_STATE 0
 #endif
 
 __attribute__ ((weak))
 void backlight_init_ports(void)
 {
 
-  // Setup backlight pin as output and output low.
+  // Setup backlight pin as output and output to on state.
   // DDRx |= n
   _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
-  // PORTx &= ~n
-  _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
+  #if BACKLIGHT_ON_STATE == 0
+    // PORTx &= ~n
+    _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
+  #else
+    // PORTx |= n
+    _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
+  #endif
 
-  // Use full 16-bit resolution.
-  ICR1 = 0xFFFF;
+  #ifndef NO_BACKLIGHT_CLOCK
+    // Use full 16-bit resolution.
+    ICR1 = 0xFFFF;
 
-  // I could write a wall of text here to explain... but TL;DW
-  // Go read the ATmega32u4 datasheet.
-  // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
+    // I could write a wall of text here to explain... but TL;DW
+    // Go read the ATmega32u4 datasheet.
+    // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
 
-  // Pin PB7 = OCR1C (Timer 1, Channel C)
-  // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
-  // (i.e. start high, go low when counter matches.)
-  // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
-  // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
+    // Pin PB7 = OCR1C (Timer 1, Channel C)
+    // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
+    // (i.e. start high, go low when counter matches.)
+    // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
+    // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
 
-  TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
-  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+    TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
+    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+  #endif
 
   backlight_init();
   #ifdef BACKLIGHT_BREATHING
@@ -562,24 +668,43 @@ __attribute__ ((weak))
 void backlight_set(uint8_t level)
 {
   // Prevent backlight blink on lowest level
-  // PORTx &= ~n
-  _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
+  #if BACKLIGHT_ON_STATE == 0
+    // PORTx &= ~n
+    _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
+  #else
+    // PORTx |= n
+    _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
+  #endif
 
   if ( level == 0 ) {
-    // Turn off PWM control on backlight pin, revert to output low.
-    TCCR1A &= ~(_BV(COM1x1));
-    OCR1x = 0x0;
-  } else if ( level == BACKLIGHT_LEVELS ) {
-    // Turn on PWM control of backlight pin
-    TCCR1A |= _BV(COM1x1);
-    // Set the brightness
-    OCR1x = 0xFFFF;
-  } else {
-    // Turn on PWM control of backlight pin
-    TCCR1A |= _BV(COM1x1);
-    // Set the brightness
-    OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
-  }
+    #ifndef NO_BACKLIGHT_CLOCK
+      // Turn off PWM control on backlight pin, revert to output low.
+      TCCR1A &= ~(_BV(COM1x1));
+      OCR1x = 0x0;
+    #else
+      #if BACKLIGHT_ON_STATE == 0
+        // PORTx |= n
+        _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
+      #else
+        // PORTx &= ~n
+        _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
+      #endif
+    #endif
+  } 
+  #ifndef NO_BACKLIGHT_CLOCK
+    else if ( level == BACKLIGHT_LEVELS ) {
+      // Turn on PWM control of backlight pin
+      TCCR1A |= _BV(COM1x1);
+      // Set the brightness
+      OCR1x = 0xFFFF;
+    } 
+    else {
+      // Turn on PWM control of backlight pin
+      TCCR1A |= _BV(COM1x1);
+      // Set the brightness
+      OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
+    }
+  #endif
 
   #ifdef BACKLIGHT_BREATHING
     breathing_intensity_default();
diff --git a/quantum/quantum.h b/quantum/quantum.h
index e6adf974ab..18f072189d 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -15,7 +15,6 @@
 #ifdef RGBLIGHT_ENABLE
   #include "rgblight.h"
 #endif
-
 #include "action_layer.h"
 #include "eeconfig.h"
 #include <stddef.h>
@@ -63,6 +62,10 @@ extern uint32_t default_layer_state;
 	#include "process_printer.h"
 #endif
 
+#ifdef COMBO_ENABLE
+	#include "process_combo.h"
+#endif
+
 #define SEND_STRING(str) send_string(PSTR(str))
 void send_string(const char *str);
 
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
new file mode 100644
index 0000000000..cc7a5013f6
--- /dev/null
+++ b/quantum/quantum_keycodes.h
@@ -0,0 +1,351 @@
+
+#ifndef QUANTUM_KEYCODES_H
+#define QUANTUM_KEYCODES_H
+
+enum quantum_keycodes {
+    // Ranges used in shortucuts - not to be used directly
+    QK_TMK                = 0x0000,
+    QK_TMK_MAX            = 0x00FF,
+    QK_MODS               = 0x0100,
+    QK_LCTL               = 0x0100,
+    QK_LSFT               = 0x0200,
+    QK_LALT               = 0x0400,
+    QK_LGUI               = 0x0800,
+    QK_RMODS_MIN          = 0x1000,
+    QK_RCTL               = 0x1100,
+    QK_RSFT               = 0x1200,
+    QK_RALT               = 0x1400,
+    QK_RGUI               = 0x1800,
+    QK_MODS_MAX           = 0x1FFF,
+    QK_FUNCTION           = 0x2000,
+    QK_FUNCTION_MAX       = 0x2FFF,
+    QK_MACRO              = 0x3000,
+    QK_MACRO_MAX          = 0x3FFF,
+    QK_LAYER_TAP          = 0x4000,
+    QK_LAYER_TAP_MAX      = 0x4FFF,
+    QK_TO                 = 0x5000,
+    QK_TO_MAX             = 0x50FF,
+    QK_MOMENTARY          = 0x5100,
+    QK_MOMENTARY_MAX      = 0x51FF,
+    QK_DEF_LAYER          = 0x5200,
+    QK_DEF_LAYER_MAX      = 0x52FF,
+    QK_TOGGLE_LAYER       = 0x5300,
+    QK_TOGGLE_LAYER_MAX   = 0x53FF,
+    QK_ONE_SHOT_LAYER     = 0x5400,
+    QK_ONE_SHOT_LAYER_MAX = 0x54FF,
+    QK_ONE_SHOT_MOD       = 0x5500,
+    QK_ONE_SHOT_MOD_MAX   = 0x55FF,
+#ifndef DISABLE_CHORDING
+    QK_CHORDING           = 0x5600,
+    QK_CHORDING_MAX       = 0x56FF,
+#endif
+    QK_TAP_DANCE          = 0x5700,
+    QK_TAP_DANCE_MAX      = 0x57FF,
+#ifdef UNICODEMAP_ENABLE
+    QK_UNICODE_MAP        = 0x5800,
+    QK_UNICODE_MAP_MAX    = 0x5BFF,
+#endif
+    QK_MOD_TAP            = 0x6000,
+    QK_MOD_TAP_MAX        = 0x7FFF,
+#ifdef UNICODE_ENABLE
+    QK_UNICODE            = 0x8000,
+    QK_UNICODE_MAX        = 0xFFFF,
+#endif
+
+    // Loose keycodes - to be used directly
+
+    RESET = 0x5C00,
+    DEBUG,
+    MAGIC_SWAP_CONTROL_CAPSLOCK,
+    MAGIC_CAPSLOCK_TO_CONTROL,
+    MAGIC_SWAP_LALT_LGUI,
+    MAGIC_SWAP_RALT_RGUI,
+    MAGIC_NO_GUI,
+    MAGIC_SWAP_GRAVE_ESC,
+    MAGIC_SWAP_BACKSLASH_BACKSPACE,
+    MAGIC_HOST_NKRO,
+    MAGIC_SWAP_ALT_GUI,
+    MAGIC_UNSWAP_CONTROL_CAPSLOCK,
+    MAGIC_UNCAPSLOCK_TO_CONTROL,
+    MAGIC_UNSWAP_LALT_LGUI,
+    MAGIC_UNSWAP_RALT_RGUI,
+    MAGIC_UNNO_GUI,
+    MAGIC_UNSWAP_GRAVE_ESC,
+    MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
+    MAGIC_UNHOST_NKRO,
+    MAGIC_UNSWAP_ALT_GUI,
+    MAGIC_TOGGLE_NKRO,
+
+    // Leader key
+#ifndef DISABLE_LEADER
+    KC_LEAD,
+#endif
+
+    // Audio on/off/toggle
+    AU_ON,
+    AU_OFF,
+    AU_TOG,
+
+#ifdef FAUXCLICKY_ENABLE
+    // Faux clicky
+    FC_ON,
+    FC_OFF,
+    FC_TOG,
+#endif
+
+    // Music mode on/off/toggle
+    MU_ON,
+    MU_OFF,
+    MU_TOG,
+
+    // Music voice iterate
+    MUV_IN,
+    MUV_DE,
+
+    // Midi mode on/off
+    MIDI_ON,
+    MIDI_OFF,
+
+    // Backlight functionality
+    BL_0,
+    BL_1,
+    BL_2,
+    BL_3,
+    BL_4,
+    BL_5,
+    BL_6,
+    BL_7,
+    BL_8,
+    BL_9,
+    BL_10,
+    BL_11,
+    BL_12,
+    BL_13,
+    BL_14,
+    BL_15,
+    BL_DEC,
+    BL_INC,
+    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,
+
+    // Right shift, close paren
+    KC_RSPC,
+
+    // Printing
+    PRINT_ON,
+    PRINT_OFF,
+
+    // output selection
+    OUT_AUTO,
+    OUT_USB,
+#ifdef BLUETOOTH_ENABLE
+    OUT_BT,
+#endif
+#ifdef ADAFRUIT_BLE_ENABLE
+    OUT_BLE,
+#endif
+
+    // always leave at the end
+    SAFE_RANGE
+};
+
+// Ability to use mods in layouts
+#define LCTL(kc) (kc | QK_LCTL)
+#define LSFT(kc) (kc | QK_LSFT)
+#define LALT(kc) (kc | QK_LALT)
+#define LGUI(kc) (kc | QK_LGUI)
+#define RCTL(kc) (kc | QK_RCTL)
+#define RSFT(kc) (kc | QK_RSFT)
+#define RALT(kc) (kc | QK_RALT)
+#define RGUI(kc) (kc | QK_RGUI)
+
+#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 SCMD(kc) (kc | QK_LGUI | QK_LSFT)
+#define SWIN(kc) SCMD(kc)
+
+#define MOD_HYPR 0xf
+#define MOD_MEH 0x7
+
+
+// Aliases for shifted symbols
+// Each key has a 4-letter code, and some have longer aliases too.
+// While the long aliases are descriptive, the 4-letter codes
+// make for nicer grid layouts (everything lines up), and are
+// the preferred style for Quantum.
+#define KC_TILD LSFT(KC_GRV)    // ~
+#define KC_TILDE    KC_TILD
+
+#define KC_EXLM LSFT(KC_1)      // !
+#define KC_EXCLAIM  KC_EXLM
+
+#define KC_AT   LSFT(KC_2)      // @
+
+#define KC_HASH LSFT(KC_3)      // #
+
+#define KC_DLR  LSFT(KC_4)      // $
+#define KC_DOLLAR   KC_DLR
+
+#define KC_PERC LSFT(KC_5)      // %
+#define KC_PERCENT  KC_PERC
+
+#define KC_CIRC LSFT(KC_6)      // ^
+#define KC_CIRCUMFLEX   KC_CIRC
+
+#define KC_AMPR LSFT(KC_7)      // &
+#define KC_AMPERSAND    KC_AMPR
+
+#define KC_ASTR LSFT(KC_8)      // *
+#define KC_ASTERISK KC_ASTR
+
+#define KC_LPRN LSFT(KC_9)      // (
+#define KC_LEFT_PAREN   KC_LPRN
+
+#define KC_RPRN LSFT(KC_0)      // )
+#define KC_RIGHT_PAREN  KC_RPRN
+
+#define KC_UNDS LSFT(KC_MINS)   // _
+#define KC_UNDERSCORE   KC_UNDS
+
+#define KC_PLUS LSFT(KC_EQL)    // +
+
+#define KC_LCBR LSFT(KC_LBRC)   // {
+#define KC_LEFT_CURLY_BRACE KC_LCBR
+
+#define KC_RCBR LSFT(KC_RBRC)   // }
+#define KC_RIGHT_CURLY_BRACE    KC_RCBR
+
+#define KC_LABK LSFT(KC_COMM)   // <
+#define KC_LEFT_ANGLE_BRACKET   KC_LABK
+
+#define KC_RABK LSFT(KC_DOT)    // >
+#define KC_RIGHT_ANGLE_BRACKET  KC_RABK
+
+#define KC_COLN LSFT(KC_SCLN)   // :
+#define KC_COLON    KC_COLN
+
+#define KC_PIPE LSFT(KC_BSLS)   // |
+
+#define KC_LT LSFT(KC_COMM)     // <
+
+#define KC_GT LSFT(KC_DOT)      // >
+
+#define KC_QUES LSFT(KC_SLSH)   // ?
+#define KC_QUESTION KC_QUES
+
+#define KC_DQT LSFT(KC_QUOT)   // "
+#define KC_DOUBLE_QUOTE KC_DQT
+#define KC_DQUO KC_DQT
+
+#define KC_DELT KC_DELETE // Del key (four letter code)
+
+// Alias for function layers than expand past FN31
+#define FUNC(kc) (kc | QK_FUNCTION)
+
+// Aliases
+#define S(kc) LSFT(kc)
+#define F(kc) FUNC(kc)
+
+#define M(kc) (kc | QK_MACRO)
+
+#define MACROTAP(kc) (kc | QK_MACRO | FUNC_TAP<<8)
+#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
+
+
+// L-ayer, T-ap - 256 keycode max, 16 layer max
+#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
+
+#define AG_SWAP MAGIC_SWAP_ALT_GUI
+#define AG_NORM MAGIC_UNSWAP_ALT_GUI
+
+#define BL_ON  BL_9
+#define BL_OFF BL_0
+
+#define MI_ON MIDI_ON
+#define MI_OFF MIDI_OFF
+
+// GOTO layer - 16 layers max
+// when:
+// ON_PRESS    = 1
+// ON_RELEASE  = 2
+// Unless you have a good reason not to do so, prefer  ON_PRESS (1) as your default.
+// 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)
+
+// Set default layer - 256 layer max
+#define DF(layer) (layer | QK_DEF_LAYER)
+
+// Toggle to layer - 256 layer max
+#define TG(layer) (layer | QK_TOGGLE_LAYER)
+
+// One-shot layer - 256 layer max
+#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
+
+// 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 & 0x1F) << 8))
+
+#define CTL_T(kc) MT(MOD_LCTL, kc)
+#define LCTL_T(kc) MT(MOD_LCTL, kc)
+#define RCTL_T(kc) MT(MOD_RCTL, kc)
+
+#define SFT_T(kc) MT(MOD_LSFT, kc)
+#define LSFT_T(kc) MT(MOD_LSFT, kc)
+#define RSFT_T(kc) MT(MOD_RSFT, kc)
+
+#define ALT_T(kc) MT(MOD_LALT, kc)
+#define LALT_T(kc) MT(MOD_LALT, kc)
+#define RALT_T(kc) MT(MOD_RALT, kc)
+#define ALGR_T(kc) MT(MOD_RALT, kc) // dual-function AltGR
+
+#define GUI_T(kc) MT(MOD_LGUI, kc)
+#define LGUI_T(kc) MT(MOD_LGUI, kc)
+#define RGUI_T(kc) MT(MOD_RGUI, kc)
+
+#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
+#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
+#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui
+#define RCAG_T(kc) MT((MOD_RCTL | MOD_RALT | MOD_RGUI), kc) // Right control alt and gui
+#define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
+#define SCMD_T(kc) MT((MOD_LGUI | MOD_LSFT), kc)
+#define SWIN_T(kc) SCMD_T(kc)
+
+// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
+#define KC_HYPR HYPR(KC_NO)
+#define KC_MEH  MEH(KC_NO)
+
+#ifdef UNICODE_ENABLE
+    // For sending unicode codes.
+    // You may not send codes over 7FFF -- this supports most of UTF8.
+    // To have a key that sends out Œ, go UC(0x0152)
+    #define UNICODE(n) (n | QK_UNICODE)
+    #define UC(n) UNICODE(n)
+#endif
+
+#ifdef UNICODEMAP_ENABLE
+    #define X(n) (n | QK_UNICODE_MAP)
+#endif
+
+#endif // QUANTUM_KEYCODES_H
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 625971e0fe..dd1b91c63c 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -66,6 +66,8 @@ __attribute__ ((weak))
 const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
 __attribute__ ((weak))
 const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20};
+__attribute__ ((weak))
+const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
 
 rgblight_config_t rgblight_config;
 rgblight_config_t inmem_config;
@@ -219,6 +221,14 @@ void rgblight_step(void) {
   }
   rgblight_mode(mode);
 }
+void rgblight_step_reverse(void) {
+  uint8_t mode = 0;
+  mode = rgblight_config.mode - 1;
+  if (mode < 1) {
+    mode = RGBLIGHT_MODES;
+  }
+  rgblight_mode(mode);
+}
 
 void rgblight_mode(uint8_t mode) {
   if (!rgblight_config.enable) {
@@ -237,7 +247,7 @@ void rgblight_mode(uint8_t mode) {
     #ifdef RGBLIGHT_ANIMATIONS
       rgblight_timer_disable();
     #endif
-  } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 23) {
+  } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 24) {
     // MODE 2-5, breathing
     // MODE 6-8, rainbow mood
     // MODE 9-14, rainbow swirl
@@ -247,6 +257,12 @@ void rgblight_mode(uint8_t mode) {
     #ifdef RGBLIGHT_ANIMATIONS
       rgblight_timer_enable();
     #endif
+  } else if (rgblight_config.mode >= 25 && rgblight_config.mode <= 34) {
+    // MODE 25-34, static gradient
+
+    #ifdef RGBLIGHT_ANIMATIONS
+      rgblight_timer_disable();
+    #endif
   }
   rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
 }
@@ -350,6 +366,17 @@ void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
       } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) {
         // rainbow mood and rainbow swirl, ignore the change of hue
         hue = rgblight_config.hue;
+      } else if (rgblight_config.mode >= 25 && rgblight_config.mode <= 34) {
+        // static gradient
+        uint16_t _hue;
+        int8_t direction = ((rgblight_config.mode - 25) % 2) ? -1 : 1;
+        uint16_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[(rgblight_config.mode - 25) / 2]);
+        for (uint8_t i = 0; i < RGBLED_NUM; i++) {
+          _hue = (range / RGBLED_NUM * i * direction + hue + 360) % 360;
+          dprintf("rgblight rainbow set hsv: %u,%u,%d,%u\n", i, _hue, direction, range);
+          sethsv(_hue, sat, val, (LED_TYPE *)&led[i]);
+        }
+        rgblight_set();
       }
     }
     rgblight_config.hue = hue;
@@ -370,6 +397,7 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
   rgblight_set();
 }
 
+__attribute__ ((weak))
 void rgblight_set(void) {
   if (rgblight_config.enable) {
     #ifdef RGBW
@@ -449,6 +477,9 @@ void rgblight_task(void) {
     } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) {
       // mode = 21 to 23, knight mode
       rgblight_effect_knight(rgblight_config.mode - 21);
+    } else if (rgblight_config.mode == 24) {
+      // mode = 24, christmas mode
+      rgblight_effect_christmas();
     }
   }
 }
@@ -594,4 +625,22 @@ void rgblight_effect_knight(uint8_t interval) {
   }
 }
 
+
+void rgblight_effect_christmas(void) {
+  static uint16_t current_offset = 0;
+  static uint16_t last_timer = 0;
+  uint16_t hue;
+  uint8_t i;
+  if (timer_elapsed(last_timer) < RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL) {
+    return;
+  }
+  last_timer = timer_read();
+  current_offset = (current_offset + 1) % 2;
+  for (i = 0; i < RGBLED_NUM; i++) {
+    hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + current_offset) % 2) * 120;
+    sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
+  }
+  rgblight_set();
+}
+
 #endif
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index aa1d026e0e..2b3e791bf8 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -2,7 +2,7 @@
 #define RGBLIGHT_H
 
 #ifdef RGBLIGHT_ANIMATIONS
-	#define RGBLIGHT_MODES 23
+	#define RGBLIGHT_MODES 34
 #else
 	#define RGBLIGHT_MODES 1
 #endif
@@ -22,6 +22,14 @@
 #define RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH 4
 #endif
 
+#ifndef RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL
+#define RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL 1000
+#endif
+
+#ifndef RGBLIGHT_EFFECT_CHRISTMAS_STEP
+#define RGBLIGHT_EFFECT_CHRISTMAS_STEP 2
+#endif
+
 #ifndef RGBLIGHT_HUE_STEP
 #define RGBLIGHT_HUE_STEP 10
 #endif
@@ -40,6 +48,8 @@
 #include "eeconfig.h"
 #include "light_ws2812.h"
 
+extern LED_TYPE led[RGBLED_NUM];
+
 extern const uint8_t RGBLED_BREATHING_INTERVALS[4] PROGMEM;
 extern const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[3] PROGMEM;
 extern const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[3] PROGMEM;
@@ -63,6 +73,7 @@ void rgblight_decrease(void);
 void rgblight_toggle(void);
 void rgblight_enable(void);
 void rgblight_step(void);
+void rgblight_step_reverse(void);
 void rgblight_mode(uint8_t mode);
 void rgblight_set(void);
 void rgblight_update_dword(uint32_t dword);
@@ -98,5 +109,6 @@ void rgblight_effect_rainbow_mood(uint8_t interval);
 void rgblight_effect_rainbow_swirl(uint8_t interval);
 void rgblight_effect_snake(uint8_t interval);
 void rgblight_effect_knight(uint8_t interval);
+void rgblight_effect_christmas(void);
 
 #endif
diff --git a/quantum/template/config.h b/quantum/template/config.h
index b02f0c7ebc..c61c4a6181 100644
--- a/quantum/template/config.h
+++ b/quantum/template/config.h
@@ -46,7 +46,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define MATRIX_COL_PINS { F1, F0, B0 }
 #define UNUSED_PINS
 
-/* COL2ROW or ROW2COL */
+/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
 #define DIODE_DIRECTION COL2ROW
  
 // #define BACKLIGHT_PIN B7
diff --git a/quantum/template/rules.mk b/quantum/template/rules.mk
index 55898147dd..bad3387bf4 100644
--- a/quantum/template/rules.mk
+++ b/quantum/template/rules.mk
@@ -65,3 +65,4 @@ MIDI_ENABLE ?= no            # MIDI controls
 UNICODE_ENABLE ?= no         # Unicode
 BLUETOOTH_ENABLE ?= no       # Enable Bluetooth with the Adafruit EZ-Key HID
 AUDIO_ENABLE ?= no           # Audio output on port C6
+FAUXCLICKY_ENABLE ?= no      # Use buzzer to emulate clicky switches
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
index 54f6faaa42..5826d909e4 100644
--- a/quantum/visualizer/visualizer.c
+++ b/quantum/visualizer/visualizer.c
@@ -53,10 +53,13 @@ SOFTWARE.
 #define "Visualizer thread priority not defined"
 #endif
 
+// mods status
+#include "action_util.h"
 
 static visualizer_keyboard_status_t current_status = {
     .layer = 0xFFFFFFFF,
     .default_layer = 0xFFFFFFFF,
+    .mods = 0xFF,
     .leds = 0xFFFFFFFF,
     .suspended = false,
 };
@@ -64,6 +67,7 @@ static visualizer_keyboard_status_t current_status = {
 static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
     return status1->layer == status2->layer &&
         status1->default_layer == status2->default_layer &&
+        status1->mods == status2->mods &&
         status1->leds == status2->leds &&
         status1->suspended == status2->suspended;
 }
@@ -307,6 +311,45 @@ bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_s
     gdispFlush();
     return false;
 }
+
+static void format_mods_bitmap_string(uint8_t mods, char* buffer) {
+    *buffer = ' ';
+    ++buffer;
+
+    for (int i = 0; i<8; i++)
+    {
+        uint32_t mask = (1u << i);
+        if (mods & mask) {
+            *buffer = '1';
+        } else {
+            *buffer = '0';
+        }
+        ++buffer;
+
+        if (i==3) {
+            *buffer = ' ';
+            ++buffer;
+        }
+    }
+    *buffer = 0;
+}
+
+bool keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+
+    const char* title = "Modifier states";
+    const char* mods_header = " CSAG CSAG ";
+    char status_buffer[12]; 
+    
+    gdispClear(White);
+    gdispDrawString(0, 0, title, state->font_fixed5x8, Black);
+    gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black);
+    format_mods_bitmap_string(state->status.mods, status_buffer);
+    gdispDrawString(0, 20, status_buffer, state->font_fixed5x8, Black);
+
+    gdispFlush();
+    return false;
+}
 #endif // LCD_ENABLE
 
 bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
@@ -350,6 +393,7 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
     visualizer_keyboard_status_t initial_status = {
         .default_layer = 0xFFFFFFFF,
         .layer = 0xFFFFFFFF,
+        .mods = 0xFF,
         .leds = 0xFFFFFFFF,
         .suspended = false,
     };
@@ -499,7 +543,18 @@ void update_status(bool changed) {
 #endif
 }
 
-void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
+uint8_t visualizer_get_mods() {
+  uint8_t mods = get_mods();
+
+#ifndef NO_ACTION_ONESHOT
+  if (!has_oneshot_mods_timed_out()) {
+    mods |= get_oneshot_mods();
+  }
+#endif  
+  return mods;
+}
+
+void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds) {
     // Note that there's a small race condition here, the thread could read
     // a state where one of these are set but not the other. But this should
     // not really matter as it will be fixed during the next loop step.
@@ -523,6 +578,7 @@ void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
         visualizer_keyboard_status_t new_status = {
             .layer = state,
             .default_layer = default_state,
+            .mods = mods,
             .leds = leds,
             .suspended = current_status.suspended,
         };
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
index 53e250725c..315af50228 100644
--- a/quantum/visualizer/visualizer.h
+++ b/quantum/visualizer/visualizer.h
@@ -34,10 +34,14 @@ SOFTWARE.
 #include "lcd_backlight.h"
 #endif
 
+// use this function to merget both real_mods and oneshot_mods in a uint16_t
+uint8_t visualizer_get_mods(void);
+
 // This need to be called once at the start
 void visualizer_init(void);
 // This should be called at every matrix scan
-void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds);
+void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds);
+
 // This should be called when the keyboard goes to suspend state
 void visualizer_suspend(void);
 // This should be called when the keyboard wakes up from suspend state
@@ -61,6 +65,7 @@ struct keyframe_animation_t;
 typedef struct {
     uint32_t layer;
     uint32_t default_layer;
+    uint8_t mods;
     uint32_t leds; // See led.h for available statuses
     bool suspended;
 } visualizer_keyboard_status_t;
@@ -129,6 +134,8 @@ bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_st
 bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
 // Displays a bitmap (0/1) of all the currently active layers
 bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays a bitmap (0/1) of all the currently active mods
+bool keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
 
 bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
 bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);