From 3ecb0a80af9e4ce4194a34032642933641730706 Mon Sep 17 00:00:00 2001
From: Ryan <fauxpark@gmail.com>
Date: Sat, 2 Jul 2022 22:10:08 +1000
Subject: [PATCH] Feature-ify Send String (#17275)

---
 builddefs/common_features.mk                  |   8 +-
 docs/_summary.md                              |   1 +
 docs/feature_macros.md                        |   2 +
 docs/feature_send_string.md                   | 224 ++++++++
 quantum/process_keycode/process_auto_shift.c  |   2 +
 .../process_dynamic_tapping_term.c            |   2 +
 quantum/quantum.h                             |   5 +-
 quantum/send_string.h                         |  54 --
 quantum/{ => send_string}/send_string.c       | 126 ++---
 quantum/send_string/send_string.h             | 152 ++++++
 quantum/send_string/send_string_keycodes.h    | 434 +++++++++++++++
 quantum/send_string_keycodes.h                | 505 ------------------
 12 files changed, 892 insertions(+), 623 deletions(-)
 create mode 100644 docs/feature_send_string.md
 delete mode 100644 quantum/send_string.h
 rename quantum/{ => send_string}/send_string.c (89%)
 create mode 100644 quantum/send_string/send_string.h
 create mode 100644 quantum/send_string/send_string_keycodes.h
 delete mode 100644 quantum/send_string_keycodes.h

diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index c11e5688e3..5cc4508307 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -15,7 +15,6 @@
 
 QUANTUM_SRC += \
     $(QUANTUM_DIR)/quantum.c \
-    $(QUANTUM_DIR)/send_string.c \
     $(QUANTUM_DIR)/bitwise.c \
     $(QUANTUM_DIR)/led.c \
     $(QUANTUM_DIR)/action.c \
@@ -774,6 +773,13 @@ ifeq ($(strip $(MAGIC_ENABLE)), yes)
     OPT_DEFS += -DMAGIC_KEYCODE_ENABLE
 endif
 
+SEND_STRING_ENABLE ?= yes
+ifeq ($(strip $(SEND_STRING_ENABLE)), yes)
+    OPT_DEFS += -DSEND_STRING_ENABLE
+    COMMON_VPATH += $(QUANTUM_DIR)/send_string
+    SRC += $(QUANTUM_DIR)/send_string/send_string.c
+endif
+
 ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
     SRC += $(QUANTUM_DIR)/process_keycode/process_auto_shift.c
     OPT_DEFS += -DAUTO_SHIFT_ENABLE
diff --git a/docs/_summary.md b/docs/_summary.md
index da007bccb6..b5746ff6de 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -84,6 +84,7 @@
     * [One Shot Keys](one_shot_keys.md)
     * [Pointing Device](feature_pointing_device.md)
     * [Raw HID](feature_rawhid.md)
+    * [Send String](feature_send_string.md)
     * [Sequencer](feature_sequencer.md)
     * [Swap Hands](feature_swap_hands.md)
     * [Tap Dance](feature_tap_dance.md)
diff --git a/docs/feature_macros.md b/docs/feature_macros.md
index 78bc4ba0a5..f5b163d5df 100644
--- a/docs/feature_macros.md
+++ b/docs/feature_macros.md
@@ -106,6 +106,8 @@ Only basic keycodes (prefixed by `KC_`) are supported. Do not include the `KC_`
 
 ### `SEND_STRING()` & `process_record_user`
 
+See also: [Send String](feature_send_string.md)
+
 Sometimes you want a key to type out words or phrases. For the most common situations, we've provided `SEND_STRING()`, which will type out a string (i.e. a sequence of characters) for you. All ASCII characters that are easily translatable to a keycode are supported (e.g. `qmk 123\n\t`).
 
 Here is an example `keymap.c` for a two-key keyboard:
diff --git a/docs/feature_send_string.md b/docs/feature_send_string.md
new file mode 100644
index 0000000000..67df0224e9
--- /dev/null
+++ b/docs/feature_send_string.md
@@ -0,0 +1,224 @@
+# Send String
+
+The Send String API is part of QMK's macro system. It allows for sequences of keystrokes to be sent automatically.
+
+The full ASCII character set is supported, along with all of the keycodes in the Basic Keycode range (as these are the only ones that will actually be sent to the host).
+
+?> Unicode characters are **not** supported with this API -- see the [Unicode](feature_unicode.md) feature instead.
+
+## Usage
+
+Send String is enabled by default, so there is usually no need for any special setup. However, if it is disabled, add the following to your `rules.mk`:
+
+```make
+SEND_STRING_ENABLE = yes
+```
+
+## Basic Configuration
+
+Add the following to your `config.h`:
+
+|Define           |Default         |Description                                                                                                 |
+|-----------------|----------------|------------------------------------------------------------------------------------------------------------|
+|`SENDSTRING_BELL`|*Not defined*   |If the [Audio](feature_audio.md) feature is enabled, the `\a` character (ASCII `BEL`) will beep the speaker.|
+|`BELL_SOUND`     |`TERMINAL_SOUND`|The song to play when the `\a` character is encountered. By default, this is an eighth note of C5.          |
+
+## Keycodes
+
+The Send String functions accept C string literals, but specific keycodes can be injected with the below macros. All of the keycodes in the [Basic Keycode range](keycodes_basic.md) are supported (as these are the only ones that will actually be sent to the host), but with an `X_` prefix instead of `KC_`.
+
+|Macro         |Description                                                        |
+|--------------|-------------------------------------------------------------------|
+|`SS_TAP(x)`   |Send a keydown, then keyup, event for the given Send String keycode|
+|`SS_DOWN(x)`  |Send a keydown event for the given Send String keycode             |
+|`SS_UP(x)`    |Send a keyup event for the given Send String keycode               |
+|`SS_DELAY(ms)`|Wait for `ms` milliseconds                                         |
+
+The following characters are also mapped to their respective keycodes for convenience:
+
+|Character|Hex   |ASCII|Keycode       |
+|---------|------|-----|--------------|
+|`\b`     |`\x08`|`BS` |`KC_BACKSPACE`|
+|`\e`     |`\x09`|`ESC`|`KC_ESCAPE`   |
+|`\n`     |`\x0A`|`LF` |`KC_ENTER`    |
+|`\t`     |`\x1B`|`TAB`|`KC_TAB`      |
+|         |`\x7F`|`DEL`|`KC_DELETE`   |
+
+### Language Support
+
+By default, Send String assumes your OS keyboard layout is set to US ANSI. If you are using a different keyboard layout, you can [override the lookup tables used to convert ASCII characters to keystrokes](reference_keymap_extras.md#sendstring-support).
+
+## Examples
+
+### Hello World
+
+A simple custom keycode which types out "Hello, world!" and the Enter key when pressed.
+
+Add the following to your `keymap.c`:
+
+```c
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+    switch (keycode) {
+        case SS_HELLO:
+            if (record->event.pressed) {
+                SEND_STRING("Hello, world!\n");
+            }
+            return false;
+    }
+
+    return true;
+}
+```
+
+### Keycode Injection
+
+This example types out opening and closing curly braces, then taps the left arrow key to move the cursor between the two.
+
+```c
+SEND_STRING("{}" SS_TAP(X_LEFT));
+```
+
+This example types Ctrl+A, then Ctrl+C, without releasing Ctrl.
+
+```c
+SEND_STRING(SS_LCTL("ac"));
+```
+
+## API
+
+### `void send_string(const char *string)`
+
+Type out a string of ASCII characters.
+
+This function simply calls `send_string_with_delay(string, 0)`.
+
+#### Arguments
+
+ - `const char *string`  
+   The string to type out.
+
+---
+
+### `void send_string_with_delay(const char *string, uint8_t interval)`
+
+Type out a string of ASCII characters, with a delay between each character.
+
+#### Arguments
+
+ - `const char *string`  
+   The string to type out.
+ - `uint8_t interval`  
+   The amount of time, in milliseconds, to wait before typing the next character.
+
+---
+
+### `void send_string_P(const char *string)`
+
+Type out a PROGMEM string of ASCII characters.
+
+On ARM devices, this function is simply an alias for `send_string_with_delay(string, 0)`.
+
+#### Arguments
+
+ - `const char *string`  
+   The string to type out.
+
+---
+
+### `void send_string_with_delay_P(const char *string, uint8_t interval)`
+
+Type out a PROGMEM string of ASCII characters, with a delay between each character.
+
+On ARM devices, this function is simply an alias for `send_string_with_delay(string, interval)`.
+
+#### Arguments
+
+ - `const char *string`  
+   The string to type out.
+ - `uint8_t interval`  
+   The amount of time, in milliseconds, to wait before typing the next character.
+
+---
+
+### `void send_char(char ascii_code)`
+
+Type out an ASCII character.
+
+#### Arguments
+
+ - `char ascii_code`  
+   The character to type.
+
+---
+
+### `void send_dword(uint32_t number)`
+
+Type out an eight digit (unsigned 32-bit) hexadecimal value.
+
+The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`.
+
+#### Arguments
+
+ - `uint32_t number`  
+   The value to type, from 0 to 4,294,967,295.
+
+---
+
+### `void send_word(uint16_t number)`
+
+Type out a four digit (unsigned 16-bit) hexadecimal value.
+
+The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`.
+
+#### Arguments
+
+ - `uint16_t number`  
+   The value to type, from 0 to 65,535.
+
+---
+
+### `void send_byte(uint8_t number)`
+
+Type out a two digit (8-bit) hexadecimal value.
+
+The format is `[0-9a-f]{2}`, eg. `00` through `ff`.
+
+#### Arguments
+
+ - `uint8_t number`  
+   The value to type, from 0 to 255.
+
+---
+
+### `void send_nibble(uint8_t number)`
+
+Type out a single hexadecimal digit.
+
+The format is `[0-9a-f]{1}`, eg. `0` through `f`.
+
+#### Arguments
+
+ - `uint8_t number`  
+   The value to type, from 0 to 15.
+
+---
+
+### `void tap_random_base64(void)`
+
+Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`.
+
+---
+
+### `SEND_STRING(string)`
+
+Shortcut macro for `send_string_with_delay_P(PSTR(string), 0)`.
+
+On ARM devices, this define evaluates to `send_string_with_delay(string, 0)`.
+
+---
+
+### `SEND_STRING_DELAY(string, interval)`
+
+Shortcut macro for `send_string_with_delay_P(PSTR(string), interval)`.
+
+On ARM devices, this define evaluates to `send_string_with_delay(string, interval)`.
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c
index e6a7c01f2a..8cb45bc0ae 100644
--- a/quantum/process_keycode/process_auto_shift.c
+++ b/quantum/process_keycode/process_auto_shift.c
@@ -325,11 +325,13 @@ void autoshift_disable(void) {
 
 #    ifndef AUTO_SHIFT_NO_SETUP
 void autoshift_timer_report(void) {
+#        ifdef SEND_STRING_ENABLE
     char display[8];
 
     snprintf(display, 8, "\n%d\n", autoshift_timeout);
 
     send_string((const char *)display);
+#        endif
 }
 #    endif
 
diff --git a/quantum/process_keycode/process_dynamic_tapping_term.c b/quantum/process_keycode/process_dynamic_tapping_term.c
index bdc5529e33..b682f34da6 100644
--- a/quantum/process_keycode/process_dynamic_tapping_term.c
+++ b/quantum/process_keycode/process_dynamic_tapping_term.c
@@ -22,12 +22,14 @@
 #endif
 
 static void tapping_term_report(void) {
+#ifdef SEND_STRING_ENABLE
     const char *tapping_term_str = get_u16_str(g_tapping_term, ' ');
     // Skip padding spaces
     while (*tapping_term_str == ' ') {
         tapping_term_str++;
     }
     send_string(tapping_term_str);
+#endif
 }
 
 bool process_dynamic_tapping_term(uint16_t keycode, keyrecord_t *record) {
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 8a7a20c706..f3a8a323c7 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -49,7 +49,6 @@
 #include "action_util.h"
 #include "action_tapping.h"
 #include "print.h"
-#include "send_string.h"
 #include "suspend.h"
 #include <stddef.h>
 #include <stdlib.h>
@@ -169,6 +168,10 @@ extern layer_state_t layer_state;
 #    include "hd44780.h"
 #endif
 
+#ifdef SEND_STRING_ENABLE
+#    include "send_string.h"
+#endif
+
 #ifdef HAPTIC_ENABLE
 #    include "haptic.h"
 #    include "process_haptic.h"
diff --git a/quantum/send_string.h b/quantum/send_string.h
deleted file mode 100644
index b90e6f6890..0000000000
--- a/quantum/send_string.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright 2021
- *
- * 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 <stdint.h>
-
-#include "progmem.h"
-#include "send_string_keycodes.h"
-
-#define SEND_STRING(string) send_string_P(PSTR(string))
-#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval)
-
-// Look-Up Tables (LUTs) to convert ASCII character to keycode sequence.
-extern const uint8_t ascii_to_shift_lut[16];
-extern const uint8_t ascii_to_altgr_lut[16];
-extern const uint8_t ascii_to_dead_lut[16];
-extern const uint8_t ascii_to_keycode_lut[128];
-
-// clang-format off
-#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \
-    ( ((a) ? 1 : 0) << 0 \
-    | ((b) ? 1 : 0) << 1 \
-    | ((c) ? 1 : 0) << 2 \
-    | ((d) ? 1 : 0) << 3 \
-    | ((e) ? 1 : 0) << 4 \
-    | ((f) ? 1 : 0) << 5 \
-    | ((g) ? 1 : 0) << 6 \
-    | ((h) ? 1 : 0) << 7 )
-// clang-format on
-
-void send_string(const char *str);
-void send_string_with_delay(const char *str, uint8_t interval);
-void send_string_P(const char *str);
-void send_string_with_delay_P(const char *str, uint8_t interval);
-void send_char(char ascii_code);
-
-void send_dword(uint32_t number);
-void send_word(uint16_t number);
-void send_byte(uint8_t number);
-void send_nibble(uint8_t number);
-
-void tap_random_base64(void);
diff --git a/quantum/send_string.c b/quantum/send_string/send_string.c
similarity index 89%
rename from quantum/send_string.c
rename to quantum/send_string/send_string.c
index 0de12ba12d..818a52f6dc 100644
--- a/quantum/send_string.c
+++ b/quantum/send_string/send_string.c
@@ -142,40 +142,36 @@ __attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
 // Note: we bit-pack in "reverse" order to optimize loading
 #define PGM_LOADBIT(mem, pos) ((pgm_read_byte(&((mem)[(pos) / 8])) >> ((pos) % 8)) & 0x01)
 
-void send_string(const char *str) {
-    send_string_with_delay(str, 0);
+void send_string(const char *string) {
+    send_string_with_delay(string, 0);
 }
 
-void send_string_P(const char *str) {
-    send_string_with_delay_P(str, 0);
-}
-
-void send_string_with_delay(const char *str, uint8_t interval) {
+void send_string_with_delay(const char *string, uint8_t interval) {
     while (1) {
-        char ascii_code = *str;
+        char ascii_code = *string;
         if (!ascii_code) break;
         if (ascii_code == SS_QMK_PREFIX) {
-            ascii_code = *(++str);
+            ascii_code = *(++string);
             if (ascii_code == SS_TAP_CODE) {
                 // tap
-                uint8_t keycode = *(++str);
+                uint8_t keycode = *(++string);
                 tap_code(keycode);
             } else if (ascii_code == SS_DOWN_CODE) {
                 // down
-                uint8_t keycode = *(++str);
+                uint8_t keycode = *(++string);
                 register_code(keycode);
             } else if (ascii_code == SS_UP_CODE) {
                 // up
-                uint8_t keycode = *(++str);
+                uint8_t keycode = *(++string);
                 unregister_code(keycode);
             } else if (ascii_code == SS_DELAY_CODE) {
                 // delay
                 int     ms      = 0;
-                uint8_t keycode = *(++str);
+                uint8_t keycode = *(++string);
                 while (isdigit(keycode)) {
                     ms *= 10;
                     ms += keycode - '0';
-                    keycode = *(++str);
+                    keycode = *(++string);
                 }
                 while (ms--)
                     wait_ms(1);
@@ -183,50 +179,7 @@ void send_string_with_delay(const char *str, uint8_t interval) {
         } else {
             send_char(ascii_code);
         }
-        ++str;
-        // interval
-        {
-            uint8_t ms = interval;
-            while (ms--)
-                wait_ms(1);
-        }
-    }
-}
-
-void send_string_with_delay_P(const char *str, uint8_t interval) {
-    while (1) {
-        char ascii_code = pgm_read_byte(str);
-        if (!ascii_code) break;
-        if (ascii_code == SS_QMK_PREFIX) {
-            ascii_code = pgm_read_byte(++str);
-            if (ascii_code == SS_TAP_CODE) {
-                // tap
-                uint8_t keycode = pgm_read_byte(++str);
-                tap_code(keycode);
-            } else if (ascii_code == SS_DOWN_CODE) {
-                // down
-                uint8_t keycode = pgm_read_byte(++str);
-                register_code(keycode);
-            } else if (ascii_code == SS_UP_CODE) {
-                // up
-                uint8_t keycode = pgm_read_byte(++str);
-                unregister_code(keycode);
-            } else if (ascii_code == SS_DELAY_CODE) {
-                // delay
-                int     ms      = 0;
-                uint8_t keycode = pgm_read_byte(++str);
-                while (isdigit(keycode)) {
-                    ms *= 10;
-                    ms += keycode - '0';
-                    keycode = pgm_read_byte(++str);
-                }
-                while (ms--)
-                    wait_ms(1);
-            }
-        } else {
-            send_char(ascii_code);
-        }
-        ++str;
+        ++string;
         // interval
         {
             uint8_t ms = interval;
@@ -250,17 +203,17 @@ void send_char(char ascii_code) {
     bool    is_dead    = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code);
 
     if (is_shifted) {
-        register_code(KC_LSFT);
+        register_code(KC_LEFT_SHIFT);
     }
     if (is_altgred) {
-        register_code(KC_RALT);
+        register_code(KC_RIGHT_ALT);
     }
     tap_code(keycode);
     if (is_altgred) {
-        unregister_code(KC_RALT);
+        unregister_code(KC_RIGHT_ALT);
     }
     if (is_shifted) {
-        unregister_code(KC_LSFT);
+        unregister_code(KC_LEFT_SHIFT);
     }
     if (is_dead) {
         tap_code(KC_SPACE);
@@ -320,3 +273,52 @@ void tap_random_base64(void) {
             break;
     }
 }
+
+#if defined(__AVR__)
+void send_string_P(const char *string) {
+    send_string_with_delay_P(string, 0);
+}
+
+void send_string_with_delay_P(const char *string, uint8_t interval) {
+    while (1) {
+        char ascii_code = pgm_read_byte(string);
+        if (!ascii_code) break;
+        if (ascii_code == SS_QMK_PREFIX) {
+            ascii_code = pgm_read_byte(++string);
+            if (ascii_code == SS_TAP_CODE) {
+                // tap
+                uint8_t keycode = pgm_read_byte(++string);
+                tap_code(keycode);
+            } else if (ascii_code == SS_DOWN_CODE) {
+                // down
+                uint8_t keycode = pgm_read_byte(++string);
+                register_code(keycode);
+            } else if (ascii_code == SS_UP_CODE) {
+                // up
+                uint8_t keycode = pgm_read_byte(++string);
+                unregister_code(keycode);
+            } else if (ascii_code == SS_DELAY_CODE) {
+                // delay
+                int     ms      = 0;
+                uint8_t keycode = pgm_read_byte(++string);
+                while (isdigit(keycode)) {
+                    ms *= 10;
+                    ms += keycode - '0';
+                    keycode = pgm_read_byte(++string);
+                }
+                while (ms--)
+                    wait_ms(1);
+            }
+        } else {
+            send_char(ascii_code);
+        }
+        ++string;
+        // interval
+        {
+            uint8_t ms = interval;
+            while (ms--)
+                wait_ms(1);
+        }
+    }
+}
+#endif
diff --git a/quantum/send_string/send_string.h b/quantum/send_string/send_string.h
new file mode 100644
index 0000000000..4eb55b88dc
--- /dev/null
+++ b/quantum/send_string/send_string.h
@@ -0,0 +1,152 @@
+/* Copyright 2021
+ *
+ * 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/>.
+ */
+
+/**
+ * \defgroup send_string
+ *
+ * Send String API. These functions allow you to create macros by typing out sequences of keystrokes.
+ * \{
+ */
+
+#include <stdint.h>
+
+#include "progmem.h"
+#include "send_string_keycodes.h"
+
+// Look-Up Tables (LUTs) to convert ASCII character to keycode sequence.
+extern const uint8_t ascii_to_shift_lut[16];
+extern const uint8_t ascii_to_altgr_lut[16];
+extern const uint8_t ascii_to_dead_lut[16];
+extern const uint8_t ascii_to_keycode_lut[128];
+
+// clang-format off
+#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \
+    ( ((a) ? 1 : 0) << 0 \
+    | ((b) ? 1 : 0) << 1 \
+    | ((c) ? 1 : 0) << 2 \
+    | ((d) ? 1 : 0) << 3 \
+    | ((e) ? 1 : 0) << 4 \
+    | ((f) ? 1 : 0) << 5 \
+    | ((g) ? 1 : 0) << 6 \
+    | ((h) ? 1 : 0) << 7 )
+// clang-format on
+
+/**
+ * \brief Type out a string of ASCII characters.
+ *
+ * This function simply calls `send_string_with_delay(string, 0)`.
+ *
+ * Most keycodes from the basic keycode range are also supported by way of a special sequence - see `send_string_keycodes.h`.
+ *
+ * \param string The string to type out.
+ */
+void send_string(const char *string);
+
+/**
+ * \brief Type out a string of ASCII characters, with a delay between each character.
+ *
+ * \param string The string to type out.
+ * \param interval The amount of time, in milliseconds, to wait before typing the next character.
+ */
+void send_string_with_delay(const char *string, uint8_t interval);
+
+/**
+ * \brief Type out an ASCII character.
+ *
+ * \param ascii_code The character to type.
+ */
+void send_char(char ascii_code);
+
+/**
+ * \brief Type out an eight digit (unsigned 32-bit) hexadecimal value.
+ *
+ * The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`.
+ *
+ * \param number The value to type, from 0 to 4,294,967,295.
+ */
+void send_dword(uint32_t number);
+
+/**
+ * \brief Type out a four digit (unsigned 16-bit) hexadecimal value.
+ *
+ * The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`.
+ *
+ * \param number The value to type, from 0 to 65,535.
+ */
+void send_word(uint16_t number);
+
+/**
+ * \brief Type out a two digit (8-bit) hexadecimal value.
+ *
+ * The format is `[0-9a-f]{2}`, eg. `00` through `ff`.
+ *
+ * \param number The value to type, from 0 to 255.
+ */
+void send_byte(uint8_t number);
+
+/**
+ * \brief Type out a single hexadecimal digit.
+ *
+ * The format is `[0-9a-f]{1}`, eg. `0` through `f`.
+ *
+ * \param number The value to type, from 0 to 15.
+ */
+void send_nibble(uint8_t number);
+
+/**
+ * \brief Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`.
+ */
+void tap_random_base64(void);
+
+#if defined(__AVR__) || defined(__DOXYGEN__)
+/**
+ * \brief Type out a PROGMEM string of ASCII characters.
+ *
+ * On ARM devices, this function is simply an alias for send_string_with_delay(string, 0).
+ *
+ * \param string The string to type out.
+ */
+void send_string_P(const char *string);
+
+/**
+ * \brief Type out a PROGMEM string of ASCII characters, with a delay between each character.
+ *
+ * On ARM devices, this function is simply an alias for send_string_with_delay(string, interval).
+ *
+ * \param string The string to type out.
+ * \param interval The amount of time, in milliseconds, to wait before typing the next character.
+ */
+void send_string_with_delay_P(const char *string, uint8_t interval);
+#else
+#    define send_string_P(string) send_string_with_delay(string, 0)
+#    define send_string_with_delay_P(string, interval) send_string_with_delay(string, interval)
+#endif
+
+/**
+ * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), 0).
+ *
+ * On ARM devices, this define evaluates to send_string_with_delay(string, 0).
+ */
+#define SEND_STRING(string) send_string_with_delay_P(PSTR(string), 0)
+
+/**
+ * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), interval).
+ *
+ * On ARM devices, this define evaluates to send_string_with_delay(string, interval).
+ */
+#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval)
+
+/** \} */
diff --git a/quantum/send_string/send_string_keycodes.h b/quantum/send_string/send_string_keycodes.h
new file mode 100644
index 0000000000..7017e03d5a
--- /dev/null
+++ b/quantum/send_string/send_string_keycodes.h
@@ -0,0 +1,434 @@
+/* Copyright 2019
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+// clang-format off
+
+/* Punctuation */
+#define X_ENT  X_ENTER
+#define X_ESC  X_ESCAPE
+#define X_BSPC X_BSPACE
+#define X_SPC  X_SPACE
+#define X_MINS X_MINUS
+#define X_EQL  X_EQUAL
+#define X_LBRC X_LBRACKET
+#define X_RBRC X_RBRACKET
+#define X_BSLS X_BSLASH
+#define X_NUHS X_NONUS_HASH
+#define X_SCLN X_SCOLON
+#define X_QUOT X_QUOTE
+#define X_GRV  X_GRAVE
+#define X_COMM X_COMMA
+#define X_SLSH X_SLASH
+#define X_NUBS X_NONUS_BSLASH
+
+/* Lock Keys */
+#define X_CLCK X_CAPSLOCK
+#define X_CAPS X_CAPSLOCK
+#define X_SLCK X_SCROLLLOCK
+#define X_NLCK X_NUMLOCK
+#define X_LCAP X_LOCKING_CAPS
+#define X_LNUM X_LOCKING_NUM
+#define X_LSCR X_LOCKING_SCROLL
+
+/* Commands */
+#define X_PSCR X_PSCREEN
+#define X_PAUS X_PAUSE
+#define X_BRK  X_PAUSE
+#define X_INS  X_INSERT
+#define X_DEL  X_DELETE
+#define X_PGDN X_PGDOWN
+#define X_RGHT X_RIGHT
+#define X_APP  X_APPLICATION
+#define X_EXEC X_EXECUTE
+#define X_SLCT X_SELECT
+#define X_AGIN X_AGAIN
+#define X_PSTE X_PASTE
+#define X_ERAS X_ALT_ERASE
+#define X_CLR  X_CLEAR
+
+/* Keypad */
+#define X_PSLS X_KP_SLASH
+#define X_PAST X_KP_ASTERISK
+#define X_PMNS X_KP_MINUS
+#define X_PPLS X_KP_PLUS
+#define X_PENT X_KP_ENTER
+#define X_P1   X_KP_1
+#define X_P2   X_KP_2
+#define X_P3   X_KP_3
+#define X_P4   X_KP_4
+#define X_P5   X_KP_5
+#define X_P6   X_KP_6
+#define X_P7   X_KP_7
+#define X_P8   X_KP_8
+#define X_P9   X_KP_9
+#define X_P0   X_KP_0
+#define X_PDOT X_KP_DOT
+#define X_PEQL X_KP_EQUAL
+#define X_PCMM X_KP_COMMA
+
+/* Japanese specific */
+#define X_ZKHK X_GRAVE
+#define X_RO   X_INT1
+#define X_KANA X_INT2
+#define X_JYEN X_INT3
+#define X_HENK X_INT4
+#define X_MHEN X_INT5
+
+/* Korean specific */
+#define X_HAEN X_LANG1
+#define X_HANJ X_LANG2
+
+/* Modifiers */
+#define X_LCTL X_LCTRL
+#define X_LSFT X_LSHIFT
+#define X_LOPT X_LALT
+#define X_LCMD X_LGUI
+#define X_LWIN X_LGUI
+#define X_RCTL X_RCTRL
+#define X_RSFT X_RSHIFT
+#define X_ALGR X_RALT
+#define X_ROPT X_RALT
+#define X_RCMD X_RGUI
+#define X_RWIN X_RGUI
+
+/* Generic Desktop Page (0x01) */
+#define X_PWR  X_SYSTEM_POWER
+#define X_SLEP X_SYSTEM_SLEEP
+#define X_WAKE X_SYSTEM_WAKE
+
+/* Consumer Page (0x0C) */
+#define X_MUTE X_AUDIO_MUTE
+#define X_VOLU X_AUDIO_VOL_UP
+#define X_VOLD X_AUDIO_VOL_DOWN
+#define X_MNXT X_MEDIA_NEXT_TRACK
+#define X_MPRV X_MEDIA_PREV_TRACK
+#define X_MSTP X_MEDIA_STOP
+#define X_MPLY X_MEDIA_PLAY_PAUSE
+#define X_MSEL X_MEDIA_SELECT
+#define X_EJCT X_MEDIA_EJECT
+#define X_CALC X_CALCULATOR
+#define X_MYCM X_MY_COMPUTER
+#define X_WSCH X_WWW_SEARCH
+#define X_WHOM X_WWW_HOME
+#define X_WBAK X_WWW_BACK
+#define X_WFWD X_WWW_FORWARD
+#define X_WSTP X_WWW_STOP
+#define X_WREF X_WWW_REFRESH
+#define X_WFAV X_WWW_FAVORITES
+#define X_MFFD X_MEDIA_FAST_FORWARD
+#define X_MRWD X_MEDIA_REWIND
+#define X_BRIU X_BRIGHTNESS_UP
+#define X_BRID X_BRIGHTNESS_DOWN
+
+/* System Specific */
+#define X_BRMU X_PAUSE
+#define X_BRMD X_SCROLLLOCK
+
+/* Mouse Keys */
+#define X_MS_U X_MS_UP
+#define X_MS_D X_MS_DOWN
+#define X_MS_L X_MS_LEFT
+#define X_MS_R X_MS_RIGHT
+#define X_BTN1 X_MS_BTN1
+#define X_BTN2 X_MS_BTN2
+#define X_BTN3 X_MS_BTN3
+#define X_BTN4 X_MS_BTN4
+#define X_BTN5 X_MS_BTN5
+#define X_WH_U X_MS_WH_UP
+#define X_WH_D X_MS_WH_DOWN
+#define X_WH_L X_MS_WH_LEFT
+#define X_WH_R X_MS_WH_RIGHT
+#define X_ACL0 X_MS_ACCEL0
+#define X_ACL1 X_MS_ACCEL1
+#define X_ACL2 X_MS_ACCEL2
+
+/* Keyboard/Keypad Page (0x07) */
+#define X_A                  04
+#define X_B                  05
+#define X_C                  06
+#define X_D                  07
+#define X_E                  08
+#define X_F                  09
+#define X_G                  0a
+#define X_H                  0b
+#define X_I                  0c
+#define X_J                  0d
+#define X_K                  0e
+#define X_L                  0f
+#define X_M                  10
+#define X_N                  11
+#define X_O                  12
+#define X_P                  13
+#define X_Q                  14
+#define X_R                  15
+#define X_S                  16
+#define X_T                  17
+#define X_U                  18
+#define X_V                  19
+#define X_W                  1a
+#define X_X                  1b
+#define X_Y                  1c
+#define X_Z                  1d
+#define X_1                  1e
+#define X_2                  1f
+#define X_3                  20
+#define X_4                  21
+#define X_5                  22
+#define X_6                  23
+#define X_7                  24
+#define X_8                  25
+#define X_9                  26
+#define X_0                  27
+#define X_ENTER              28
+#define X_ESCAPE             29
+#define X_BSPACE             2a
+#define X_TAB                2b
+#define X_SPACE              2c
+#define X_MINUS              2d
+#define X_EQUAL              2e
+#define X_LBRACKET           2f
+#define X_RBRACKET           30
+#define X_BSLASH             31
+#define X_NONUS_HASH         32
+#define X_SCOLON             33
+#define X_QUOTE              34
+#define X_GRAVE              35
+#define X_COMMA              36
+#define X_DOT                37
+#define X_SLASH              38
+#define X_CAPSLOCK           39
+#define X_F1                 3a
+#define X_F2                 3b
+#define X_F3                 3c
+#define X_F4                 3d
+#define X_F5                 3e
+#define X_F6                 3f
+#define X_F7                 40
+#define X_F8                 41
+#define X_F9                 42
+#define X_F10                43
+#define X_F11                44
+#define X_F12                45
+#define X_PSCREEN            46
+#define X_SCROLLLOCK         47
+#define X_PAUSE              48
+#define X_INSERT             49
+#define X_HOME               4a
+#define X_PGUP               4b
+#define X_DELETE             4c
+#define X_END                4d
+#define X_PGDOWN             4e
+#define X_RIGHT              4f
+#define X_LEFT               50
+#define X_DOWN               51
+#define X_UP                 52
+#define X_NUMLOCK            53
+#define X_KP_SLASH           54
+#define X_KP_ASTERISK        55
+#define X_KP_MINUS           56
+#define X_KP_PLUS            57
+#define X_KP_ENTER           58
+#define X_KP_1               59
+#define X_KP_2               5a
+#define X_KP_3               5b
+#define X_KP_4               5c
+#define X_KP_5               5d
+#define X_KP_6               5e
+#define X_KP_7               5f
+#define X_KP_8               60
+#define X_KP_9               61
+#define X_KP_0               62
+#define X_KP_DOT             63
+#define X_NONUS_BSLASH       64
+#define X_APPLICATION        65
+#define X_POWER              66
+#define X_KP_EQUAL           67
+#define X_F13                68
+#define X_F14                69
+#define X_F15                6a
+#define X_F16                6b
+#define X_F17                6c
+#define X_F18                6d
+#define X_F19                6e
+#define X_F20                6f
+#define X_F21                70
+#define X_F22                71
+#define X_F23                72
+#define X_F24                73
+#define X_EXECUTE            74
+#define X_HELP               75
+#define X_MENU               76
+#define X_SELECT             77
+#define X_STOP               78
+#define X_AGAIN              79
+#define X_UNDO               7a
+#define X_CUT                7b
+#define X_COPY               7c
+#define X_PASTE              7d
+#define X_FIND               7e
+#define X__MUTE              7f
+#define X__VOLUP             80
+#define X__VOLDOWN           81
+#define X_LOCKING_CAPS       82
+#define X_LOCKING_NUM        83
+#define X_LOCKING_SCROLL     84
+#define X_KP_COMMA           85
+#define X_KP_EQUAL_AS400     86
+#define X_INT1               87
+#define X_INT2               88
+#define X_INT3               89
+#define X_INT4               8a
+#define X_INT5               8b
+#define X_INT6               8c
+#define X_INT7               8d
+#define X_INT8               8e
+#define X_INT9               8f
+#define X_LANG1              90
+#define X_LANG2              91
+#define X_LANG3              92
+#define X_LANG4              93
+#define X_LANG5              94
+#define X_LANG6              95
+#define X_LANG7              96
+#define X_LANG8              97
+#define X_LANG9              98
+#define X_ALT_ERASE          99
+#define X_SYSREQ             9a
+#define X_CANCEL             9b
+#define X_CLEAR              9c
+#define X_PRIOR              9d
+#define X_RETURN             9e
+#define X_SEPARATOR          9f
+#define X_OUT                a0
+#define X_OPER               a1
+#define X_CLEAR_AGAIN        a2
+#define X_CRSEL              a3
+#define X_EXSEL              a4
+
+/* Modifiers */
+#define X_LCTRL              e0
+#define X_LSHIFT             e1
+#define X_LALT               e2
+#define X_LGUI               e3
+#define X_RCTRL              e4
+#define X_RSHIFT             e5
+#define X_RALT               e6
+#define X_RGUI               e7
+
+/* Media and Function keys */
+/* Generic Desktop Page (0x01) */
+#define X_SYSTEM_POWER       a5
+#define X_SYSTEM_SLEEP       a6
+#define X_SYSTEM_WAKE        a7
+
+/* Consumer Page (0x0C) */
+#define X_AUDIO_MUTE         a8
+#define X_AUDIO_VOL_UP       a9
+#define X_AUDIO_VOL_DOWN     aa
+#define X_MEDIA_NEXT_TRACK   ab
+#define X_MEDIA_PREV_TRACK   ac
+#define X_MEDIA_STOP         ad
+#define X_MEDIA_PLAY_PAUSE   ae
+#define X_MEDIA_SELECT       af
+#define X_MEDIA_EJECT        b0
+#define X_MAIL               b1
+#define X_CALCULATOR         b2
+#define X_MY_COMPUTER        b3
+#define X_WWW_SEARCH         b4
+#define X_WWW_HOME           b5
+#define X_WWW_BACK           b6
+#define X_WWW_FORWARD        b7
+#define X_WWW_STOP           b8
+#define X_WWW_REFRESH        b9
+#define X_WWW_FAVORITES      ba
+#define X_MEDIA_FAST_FORWARD bb
+#define X_MEDIA_REWIND       bc
+#define X_BRIGHTNESS_UP      bd
+#define X_BRIGHTNESS_DOWN    be
+
+/* Mouse Buttons (unallocated range in HID spec) */
+#ifdef VIA_ENABLE
+#define X_MS_UP              f0
+#define X_MS_DOWN            f1
+#define X_MS_LEFT            f2
+#define X_MS_RIGHT           f3
+#define X_MS_BTN1            f4
+#define X_MS_BTN2            f5
+#define X_MS_BTN3            f6
+#define X_MS_BTN4            f7
+#define X_MS_BTN5            f8
+#define X_MS_BTN6            f8
+#define X_MS_BTN7            f8
+#define X_MS_BTN8            f8
+#else
+#define X_MS_UP              ed
+#define X_MS_DOWN            ee
+#define X_MS_LEFT            ef
+#define X_MS_RIGHT           f0
+#define X_MS_BTN1            f1
+#define X_MS_BTN2            f2
+#define X_MS_BTN3            f3
+#define X_MS_BTN4            f4
+#define X_MS_BTN5            f5
+#define X_MS_BTN6            f6
+#define X_MS_BTN7            f7
+#define X_MS_BTN8            f8
+#endif
+#define X_MS_WH_UP           f9
+#define X_MS_WH_DOWN         fa
+#define X_MS_WH_LEFT         fb
+#define X_MS_WH_RIGHT        fc
+#define X_MS_ACCEL0          fd
+#define X_MS_ACCEL1          fe
+#define X_MS_ACCEL2          ff
+
+// Send string macros
+#define STRINGIZE(z) #z
+#define ADD_SLASH_X(y) STRINGIZE(\x##y)
+#define SYMBOL_STR(x) ADD_SLASH_X(x)
+
+#define SS_QMK_PREFIX 1
+
+#define SS_TAP_CODE 1
+#define SS_DOWN_CODE 2
+#define SS_UP_CODE 3
+#define SS_DELAY_CODE 4
+
+#define SS_TAP(keycode) "\1\1" SYMBOL_STR(keycode)
+#define SS_DOWN(keycode) "\1\2" SYMBOL_STR(keycode)
+#define SS_UP(keycode) "\1\3" SYMBOL_STR(keycode)
+#define SS_DELAY(msecs) "\1\4" STRINGIZE(msecs) "|"
+
+// `string` arguments must not be parenthesized
+#define SS_LCTL(string) SS_DOWN(X_LCTL) string SS_UP(X_LCTL)
+#define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT)
+#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT)
+#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI)
+#define SS_LCMD(string) SS_LGUI(string)
+#define SS_LWIN(string) SS_LGUI(string)
+
+#define SS_RCTL(string) SS_DOWN(X_RCTL) string SS_UP(X_RCTL)
+#define SS_RSFT(string) SS_DOWN(X_RSFT) string SS_UP(X_RSFT)
+#define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT)
+#define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI)
+#define SS_ALGR(string) SS_RALT(string)
+#define SS_RCMD(string) SS_RGUI(string)
+#define SS_RWIN(string) SS_RGUI(string)
+
+// DEPRECATED
+#define SS_LCTRL(string) SS_LCTL(string)
diff --git a/quantum/send_string_keycodes.h b/quantum/send_string_keycodes.h
deleted file mode 100644
index b35bf66b7b..0000000000
--- a/quantum/send_string_keycodes.h
+++ /dev/null
@@ -1,505 +0,0 @@
-/* Copyright 2019
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-// clang-format off
-
-/* Punctuation */
-#define X_ENT  X_ENTER
-#define X_ESC  X_ESCAPE
-#define X_BSPC X_BACKSPACE
-#define X_SPC  X_SPACE
-#define X_MINS X_MINUS
-#define X_EQL  X_EQUAL
-#define X_LBRC X_LEFT_BRACKET
-#define X_RBRC X_RIGHT_BRACKET
-#define X_BSLS X_BACKSLASH
-#define X_NUHS X_NONUS_HASH
-#define X_SCLN X_SEMICOLON
-#define X_QUOT X_QUOTE
-#define X_GRV  X_GRAVE
-#define X_COMM X_COMMA
-#define X_SLSH X_SLASH
-#define X_NUBS X_NONUS_BACKSLASH
-
-/* Lock Keys */
-#define X_CAPS X_CAPS_LOCK
-#define X_SCRL X_SCROLL_LOCK
-#define X_NUM  X_NUM_LOCK
-#define X_LCAP X_LOCKING_CAPS_LOCK
-#define X_LNUM X_LOCKING_NUM_LOCK
-#define X_LSCR X_LOCKING_SCROLL_LOCK
-
-/* Commands */
-#define X_PSCR X_PRINT_SCREEN
-#define X_PAUS X_PAUSE
-#define X_BRK  X_PAUSE
-#define X_INS  X_INSERT
-#define X_PGUP X_PAGE_UP
-#define X_DEL  X_DELETE
-#define X_PGDN X_PAGE_DOWN
-#define X_RGHT X_RIGHT
-#define X_APP  X_APPLICATION
-#define X_EXEC X_EXECUTE
-#define X_SLCT X_SELECT
-#define X_AGIN X_AGAIN
-#define X_PSTE X_PASTE
-#define X_ERAS X_ALTERNATE_ERASE
-#define X_SYRQ X_SYSTEM_REQUEST
-#define X_CNCL X_CANCEL
-#define X_CLR  X_CLEAR
-#define X_PRIR X_PRIOR
-#define X_RETN X_RETURN
-#define X_SEPR X_SEPARATOR
-#define X_CLAG X_CLEAR_AGAIN
-#define X_CRSL X_CRSEL
-#define X_EXSL X_EXSEL
-
-/* Keypad */
-#define X_PSLS X_KP_SLASH
-#define X_PAST X_KP_ASTERISK
-#define X_PMNS X_KP_MINUS
-#define X_PPLS X_KP_PLUS
-#define X_PENT X_KP_ENTER
-#define X_P1   X_KP_1
-#define X_P2   X_KP_2
-#define X_P3   X_KP_3
-#define X_P4   X_KP_4
-#define X_P5   X_KP_5
-#define X_P6   X_KP_6
-#define X_P7   X_KP_7
-#define X_P8   X_KP_8
-#define X_P9   X_KP_9
-#define X_P0   X_KP_0
-#define X_PDOT X_KP_DOT
-#define X_PEQL X_KP_EQUAL
-#define X_PCMM X_KP_COMMA
-
-/* Language Specific */
-#define X_INT1 X_INTERNATIONAL_1
-#define X_INT2 X_INTERNATIONAL_2
-#define X_INT3 X_INTERNATIONAL_3
-#define X_INT4 X_INTERNATIONAL_4
-#define X_INT5 X_INTERNATIONAL_5
-#define X_INT6 X_INTERNATIONAL_6
-#define X_INT7 X_INTERNATIONAL_7
-#define X_INT8 X_INTERNATIONAL_8
-#define X_INT9 X_INTERNATIONAL_9
-#define X_LNG1 X_LANGUAGE_1
-#define X_LNG2 X_LANGUAGE_2
-#define X_LNG3 X_LANGUAGE_3
-#define X_LNG4 X_LANGUAGE_4
-#define X_LNG5 X_LANGUAGE_5
-#define X_LNG6 X_LANGUAGE_6
-#define X_LNG7 X_LANGUAGE_7
-#define X_LNG8 X_LANGUAGE_8
-#define X_LNG9 X_LANGUAGE_9
-
-/* Modifiers */
-#define X_LCTL X_LEFT_CTRL
-#define X_LSFT X_LEFT_SHIFT
-#define X_LALT X_LEFT_ALT
-#define X_LOPT X_LEFT_ALT
-#define X_LGUI X_LEFT_GUI
-#define X_LCMD X_LEFT_GUI
-#define X_LWIN X_LEFT_GUI
-#define X_RCTL X_RIGHT_CTRL
-#define X_RSFT X_RIGHT_SHIFT
-#define X_RALT X_RIGHT_ALT
-#define X_ALGR X_RIGHT_ALT
-#define X_ROPT X_RIGHT_ALT
-#define X_RGUI X_RIGHT_GUI
-#define X_RCMD X_RIGHT_GUI
-#define X_RWIN X_RIGHT_GUI
-
-/* Generic Desktop Page (0x01) */
-#define X_PWR  X_SYSTEM_POWER
-#define X_SLEP X_SYSTEM_SLEEP
-#define X_WAKE X_SYSTEM_WAKE
-
-/* Consumer Page (0x0C) */
-#define X_MUTE X_AUDIO_MUTE
-#define X_VOLU X_AUDIO_VOL_UP
-#define X_VOLD X_AUDIO_VOL_DOWN
-#define X_MNXT X_MEDIA_NEXT_TRACK
-#define X_MPRV X_MEDIA_PREV_TRACK
-#define X_MSTP X_MEDIA_STOP
-#define X_MPLY X_MEDIA_PLAY_PAUSE
-#define X_MSEL X_MEDIA_SELECT
-#define X_EJCT X_MEDIA_EJECT
-#define X_CALC X_CALCULATOR
-#define X_MYCM X_MY_COMPUTER
-#define X_WSCH X_WWW_SEARCH
-#define X_WHOM X_WWW_HOME
-#define X_WBAK X_WWW_BACK
-#define X_WFWD X_WWW_FORWARD
-#define X_WSTP X_WWW_STOP
-#define X_WREF X_WWW_REFRESH
-#define X_WFAV X_WWW_FAVORITES
-#define X_MFFD X_MEDIA_FAST_FORWARD
-#define X_MRWD X_MEDIA_REWIND
-#define X_BRIU X_BRIGHTNESS_UP
-#define X_BRID X_BRIGHTNESS_DOWN
-
-/* System Specific */
-#define X_BRMU X_PAUSE
-#define X_BRMD X_SCROLL_LOCK
-
-/* Mouse Keys */
-#define X_MS_U X_MS_UP
-#define X_MS_D X_MS_DOWN
-#define X_MS_L X_MS_LEFT
-#define X_MS_R X_MS_RIGHT
-#define X_BTN1 X_MS_BTN1
-#define X_BTN2 X_MS_BTN2
-#define X_BTN3 X_MS_BTN3
-#define X_BTN4 X_MS_BTN4
-#define X_BTN5 X_MS_BTN5
-#define X_BTN6 X_MS_BTN6
-#define X_BTN7 X_MS_BTN7
-#define X_BTN8 X_MS_BTN8
-#define X_WH_U X_MS_WH_UP
-#define X_WH_D X_MS_WH_DOWN
-#define X_WH_L X_MS_WH_LEFT
-#define X_WH_R X_MS_WH_RIGHT
-#define X_ACL0 X_MS_ACCEL0
-#define X_ACL1 X_MS_ACCEL1
-#define X_ACL2 X_MS_ACCEL2
-
-/* Keyboard/Keypad Page (0x07) */
-#define X_A                   04
-#define X_B                   05
-#define X_C                   06
-#define X_D                   07
-#define X_E                   08
-#define X_F                   09
-#define X_G                   0a
-#define X_H                   0b
-#define X_I                   0c
-#define X_J                   0d
-#define X_K                   0e
-#define X_L                   0f
-#define X_M                   10
-#define X_N                   11
-#define X_O                   12
-#define X_P                   13
-#define X_Q                   14
-#define X_R                   15
-#define X_S                   16
-#define X_T                   17
-#define X_U                   18
-#define X_V                   19
-#define X_W                   1a
-#define X_X                   1b
-#define X_Y                   1c
-#define X_Z                   1d
-#define X_1                   1e
-#define X_2                   1f
-#define X_3                   20
-#define X_4                   21
-#define X_5                   22
-#define X_6                   23
-#define X_7                   24
-#define X_8                   25
-#define X_9                   26
-#define X_0                   27
-#define X_ENTER               28
-#define X_ESCAPE              29
-#define X_BACKSPACE           2a
-#define X_TAB                 2b
-#define X_SPACE               2c
-#define X_MINUS               2d
-#define X_EQUAL               2e
-#define X_LEFT_BRACKET        2f
-#define X_RIGHT_BRACKET       30
-#define X_BACKSLASH           31
-#define X_NONUS_HASH          32
-#define X_SEMICOLON           33
-#define X_QUOTE               34
-#define X_GRAVE               35
-#define X_COMMA               36
-#define X_DOT                 37
-#define X_SLASH               38
-#define X_CAPS_LOCK           39
-#define X_F1                  3a
-#define X_F2                  3b
-#define X_F3                  3c
-#define X_F4                  3d
-#define X_F5                  3e
-#define X_F6                  3f
-#define X_F7                  40
-#define X_F8                  41
-#define X_F9                  42
-#define X_F10                 43
-#define X_F11                 44
-#define X_F12                 45
-#define X_PRINT_SCREEN        46
-#define X_SCROLL_LOCK         47
-#define X_PAUSE               48
-#define X_INSERT              49
-#define X_HOME                4a
-#define X_PAGE_UP             4b
-#define X_DELETE              4c
-#define X_END                 4d
-#define X_PAGE_DOWN           4e
-#define X_RIGHT               4f
-#define X_LEFT                50
-#define X_DOWN                51
-#define X_UP                  52
-#define X_NUM_LOCK            53
-#define X_KP_SLASH            54
-#define X_KP_ASTERISK         55
-#define X_KP_MINUS            56
-#define X_KP_PLUS             57
-#define X_KP_ENTER            58
-#define X_KP_1                59
-#define X_KP_2                5a
-#define X_KP_3                5b
-#define X_KP_4                5c
-#define X_KP_5                5d
-#define X_KP_6                5e
-#define X_KP_7                5f
-#define X_KP_8                60
-#define X_KP_9                61
-#define X_KP_0                62
-#define X_KP_DOT              63
-#define X_NONUS_BACKSLASH     64
-#define X_APPLICATION         65
-#define X_KB_POWER            66
-#define X_KP_EQUAL            67
-#define X_F13                 68
-#define X_F14                 69
-#define X_F15                 6a
-#define X_F16                 6b
-#define X_F17                 6c
-#define X_F18                 6d
-#define X_F19                 6e
-#define X_F20                 6f
-#define X_F21                 70
-#define X_F22                 71
-#define X_F23                 72
-#define X_F24                 73
-#define X_EXECUTE             74
-#define X_HELP                75
-#define X_MENU                76
-#define X_SELECT              77
-#define X_STOP                78
-#define X_AGAIN               79
-#define X_UNDO                7a
-#define X_CUT                 7b
-#define X_COPY                7c
-#define X_PASTE               7d
-#define X_FIND                7e
-#define X_KB_MUTE             7f
-#define X_KB_VOLUME_UP        80
-#define X_KB_VOLUME_DOWN      81
-#define X_LOCKING_CAPS_LOCK   82
-#define X_LOCKING_NUM_LOCK    83
-#define X_LOCKING_SCROLL_LOCK 84
-#define X_KP_COMMA           85
-#define X_KP_EQUAL_AS400     86
-#define X_INTERNATIONAL_1    87
-#define X_INTERNATIONAL_2    88
-#define X_INTERNATIONAL_3    89
-#define X_INTERNATIONAL_4    8a
-#define X_INTERNATIONAL_5    8b
-#define X_INTERNATIONAL_6    8c
-#define X_INTERNATIONAL_7    8d
-#define X_INTERNATIONAL_8    8e
-#define X_INTERNATIONAL_9    8f
-#define X_LANGUAGE_1         90
-#define X_LANGUAGE_2         91
-#define X_LANGUAGE_3         92
-#define X_LANGUAGE_4         93
-#define X_LANGUAGE_5         94
-#define X_LANGUAGE_6         95
-#define X_LANGUAGE_7         96
-#define X_LANGUAGE_8         97
-#define X_LANGUAGE_9         98
-#define X_ALTERNATE_ERASE    99
-#define X_SYSTEM_REQUEST     9a
-#define X_CANCEL             9b
-#define X_CLEAR              9c
-#define X_PRIOR              9d
-#define X_RETURN             9e
-#define X_SEPARATOR          9f
-#define X_OUT                a0
-#define X_OPER               a1
-#define X_CLEAR_AGAIN        a2
-#define X_CRSEL              a3
-#define X_EXSEL              a4
-
-/* Modifiers */
-#define X_LEFT_CTRL          e0
-#define X_LEFT_SHIFT         e1
-#define X_LEFT_ALT           e2
-#define X_LEFT_GUI           e3
-#define X_RIGHT_CTRL         e4
-#define X_RIGHT_SHIFT        e5
-#define X_RIGHT_ALT          e6
-#define X_RIGHT_GUI          e7
-
-/* Media and Function keys */
-/* Generic Desktop Page (0x01) */
-#define X_SYSTEM_POWER       a5
-#define X_SYSTEM_SLEEP       a6
-#define X_SYSTEM_WAKE        a7
-
-/* Consumer Page (0x0C) */
-#define X_AUDIO_MUTE         a8
-#define X_AUDIO_VOL_UP       a9
-#define X_AUDIO_VOL_DOWN     aa
-#define X_MEDIA_NEXT_TRACK   ab
-#define X_MEDIA_PREV_TRACK   ac
-#define X_MEDIA_STOP         ad
-#define X_MEDIA_PLAY_PAUSE   ae
-#define X_MEDIA_SELECT       af
-#define X_MEDIA_EJECT        b0
-#define X_MAIL               b1
-#define X_CALCULATOR         b2
-#define X_MY_COMPUTER        b3
-#define X_WWW_SEARCH         b4
-#define X_WWW_HOME           b5
-#define X_WWW_BACK           b6
-#define X_WWW_FORWARD        b7
-#define X_WWW_STOP           b8
-#define X_WWW_REFRESH        b9
-#define X_WWW_FAVORITES      ba
-#define X_MEDIA_FAST_FORWARD bb
-#define X_MEDIA_REWIND       bc
-#define X_BRIGHTNESS_UP      bd
-#define X_BRIGHTNESS_DOWN    be
-
-/* Mouse Buttons (unallocated range in HID spec) */
-#ifdef VIA_ENABLE
-#define X_MS_UP              f0
-#define X_MS_DOWN            f1
-#define X_MS_LEFT            f2
-#define X_MS_RIGHT           f3
-#define X_MS_BTN1            f4
-#define X_MS_BTN2            f5
-#define X_MS_BTN3            f6
-#define X_MS_BTN4            f7
-#define X_MS_BTN5            f8
-#define X_MS_BTN6            f8
-#define X_MS_BTN7            f8
-#define X_MS_BTN8            f8
-#else
-#define X_MS_UP              ed
-#define X_MS_DOWN            ee
-#define X_MS_LEFT            ef
-#define X_MS_RIGHT           f0
-#define X_MS_BTN1            f1
-#define X_MS_BTN2            f2
-#define X_MS_BTN3            f3
-#define X_MS_BTN4            f4
-#define X_MS_BTN5            f5
-#define X_MS_BTN6            f6
-#define X_MS_BTN7            f7
-#define X_MS_BTN8            f8
-#endif
-#define X_MS_WH_UP           f9
-#define X_MS_WH_DOWN         fa
-#define X_MS_WH_LEFT         fb
-#define X_MS_WH_RIGHT        fc
-#define X_MS_ACCEL0          fd
-#define X_MS_ACCEL1          fe
-#define X_MS_ACCEL2          ff
-
-// Send string macros
-#define STRINGIZE(z) #z
-#define ADD_SLASH_X(y) STRINGIZE(\x##y)
-#define SYMBOL_STR(x) ADD_SLASH_X(x)
-
-#define SS_QMK_PREFIX 1
-
-#define SS_TAP_CODE 1
-#define SS_DOWN_CODE 2
-#define SS_UP_CODE 3
-#define SS_DELAY_CODE 4
-
-#define SS_TAP(keycode) "\1\1" SYMBOL_STR(keycode)
-#define SS_DOWN(keycode) "\1\2" SYMBOL_STR(keycode)
-#define SS_UP(keycode) "\1\3" SYMBOL_STR(keycode)
-#define SS_DELAY(msecs) "\1\4" STRINGIZE(msecs) "|"
-
-// `string` arguments must not be parenthesized
-#define SS_LCTL(string) SS_DOWN(X_LCTL) string SS_UP(X_LCTL)
-#define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT)
-#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT)
-#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI)
-#define SS_LCMD(string) SS_LGUI(string)
-#define SS_LWIN(string) SS_LGUI(string)
-
-#define SS_RCTL(string) SS_DOWN(X_RCTL) string SS_UP(X_RCTL)
-#define SS_RSFT(string) SS_DOWN(X_RSFT) string SS_UP(X_RSFT)
-#define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT)
-#define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI)
-#define SS_ALGR(string) SS_RALT(string)
-#define SS_RCMD(string) SS_RGUI(string)
-#define SS_RWIN(string) SS_RGUI(string)
-
-// DEPRECATED
-#define X_BSPACE         X_BACKSPACE
-#define X_LBRACKET       X_LEFT_BRACKET
-#define X_RBRACKET       X_RIGHT_BRACKET
-#define X_BSLASH         X_BACKSLASH
-#define X_SCOLON         X_SEMICOLON
-#define X_CAPSLOCK       X_CAPS_LOCK
-#define X_PSCREEN        X_PRINT_SCREEN
-#define X_SCROLLLOCK     X_SCROLL_LOCK
-#define X_PGDOWN         X_PAGE_DOWN
-#define X_NUMLOCK        X_NUM_LOCK
-#define X_NONUS_BSLASH   X_NONUS_BACKSLASH
-#define X_POWER          X_KB_POWER
-#define X__MUTE          X_KB_MUTE
-#define X__VOLUP         X_KB_VOLUME_UP
-#define X__VOLDOWN       X_KB_VOLUME_DOWN
-#define X_LOCKING_CAPS   X_LOCKING_CAPS_LOCK
-#define X_LOCKING_NUM    X_LOCKING_NUM_LOCK
-#define X_LOCKING_SCROLL X_LOCKING_SCROLL_LOCK
-#define X_LANG1          X_LANGUAGE_1
-#define X_LANG2          X_LANGUAGE_2
-#define X_LANG3          X_LANGUAGE_3
-#define X_LANG4          X_LANGUAGE_4
-#define X_LANG5          X_LANGUAGE_5
-#define X_LANG6          X_LANGUAGE_6
-#define X_LANG7          X_LANGUAGE_7
-#define X_LANG8          X_LANGUAGE_8
-#define X_LANG9          X_LANGUAGE_9
-#define X_ALT_ERASE      X_ALTERNATE_ERASE
-#define X_SYSREQ         X_SYSTEM_REQUEST
-
-#define X_LCTRL  X_LEFT_CTRL
-#define X_LSHIFT X_LEFT_SHIFT
-#define X_RCTRL  X_RIGHT_CTRL
-#define X_RSHIFT X_RIGHT_SHIFT
-
-#define X_ZKHK X_GRAVE
-#define X_RO   X_INTERNATIONAL_1
-#define X_KANA X_INTERNATIONAL_2
-#define X_JYEN X_INTERNATIONAL_3
-#define X_HENK X_INTERNATIONAL_4
-#define X_MHEN X_INTERNATIONAL_5
-#define X_HAEN X_LANGUAGE_1
-#define X_HANJ X_LANGUAGE_2
-
-#define X_CLCK X_CAPS_LOCK
-#define X_SLCK X_SCROLL_LOCK
-#define X_NLCK X_NUM_LOCK
-
-#define SS_LCTRL(string) SS_LCTL(string)