From 94fc32f43135ac4afb14849c7fb5e99f95455078 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Konstantin=20=C4=90or=C4=91evi=C4=87?=
 <vomindoraan@gmail.com>
Date: Sat, 9 May 2020 10:22:02 +0200
Subject: [PATCH] Fix bug in UC_RMOD, add shift and audio support for
 UC_MOD/UC_RMOD(#8674)

* Invert UC_MOD/UC_RMOD direction when Shift is held

Also use MOD_MASK_SHIFT in process_rgb.c

* Allow audio to be played for UC_MOD, UC_RMOD keycodes as well

* Fix signedness bug in reverse input mode cycling

* Misc formatting in process_unicode_common.c

* Address clang-format issues

* Make decode_utf8 helper function file-local (static)
---
 quantum/process_keycode/process_rgb.c         |   2 +-
 .../process_keycode/process_unicode_common.c  | 118 +++++++++++-------
 .../process_keycode/process_unicode_common.h  |   2 +-
 quantum/process_keycode/process_unicodemap.c  |   3 +-
 4 files changed, 74 insertions(+), 51 deletions(-)

diff --git a/quantum/process_keycode/process_rgb.c b/quantum/process_keycode/process_rgb.c
index 627e5986fb..21164b8f9f 100644
--- a/quantum/process_keycode/process_rgb.c
+++ b/quantum/process_keycode/process_rgb.c
@@ -56,7 +56,7 @@ bool process_rgb(const uint16_t keycode, const keyrecord_t *record) {
     // Split keyboards need to trigger on key-up for edge-case issue
     if (!record->event.pressed) {
 #endif
-        uint8_t shifted = get_mods() & (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT));
+        uint8_t shifted = get_mods() & MOD_MASK_SHIFT;
         switch (keycode) {
             case RGB_TOG:
                 rgblight_toggle();
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 48ce3961ad..fb50215012 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -24,8 +24,8 @@ uint8_t          unicode_saved_mods;
 
 #if UNICODE_SELECTED_MODES != -1
 static uint8_t selected[]     = {UNICODE_SELECTED_MODES};
-static uint8_t selected_count = sizeof selected / sizeof *selected;
-static uint8_t selected_index;
+static int8_t  selected_count = sizeof selected / sizeof *selected;
+static int8_t  selected_index;
 #endif
 
 void unicode_input_mode_init(void) {
@@ -33,7 +33,7 @@ void unicode_input_mode_init(void) {
 #if UNICODE_SELECTED_MODES != -1
 #    if UNICODE_CYCLE_PERSIST
     // Find input_mode in selected modes
-    uint8_t i;
+    int8_t i;
     for (i = 0; i < selected_count; i++) {
         if (selected[i] == unicode_config.input_mode) {
             selected_index = i;
@@ -60,9 +60,12 @@ void set_unicode_input_mode(uint8_t mode) {
     dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
 }
 
-void cycle_unicode_input_mode(uint8_t offset) {
+void cycle_unicode_input_mode(int8_t offset) {
 #if UNICODE_SELECTED_MODES != -1
-    selected_index            = (selected_index + offset) % selected_count;
+    selected_index = (selected_index + offset) % selected_count;
+    if (selected_index < 0) {
+        selected_index += selected_count;
+    }
     unicode_config.input_mode = selected[selected_index];
 #    if UNICODE_CYCLE_PERSIST
     persist_unicode_input_mode();
@@ -168,6 +171,8 @@ void register_hex32(uint32_t hex) {
     }
 }
 
+// clang-format off
+
 void send_unicode_hex_string(const char *str) {
     if (!str) {
         return;
@@ -175,12 +180,11 @@ void send_unicode_hex_string(const char *str) {
 
     while (*str) {
         // Find the next code point (token) in the string
-        for (; *str == ' '; str++)
-            ;
+        for (; *str == ' '; str++);    // Skip leading spaces
         size_t n = strcspn(str, " ");  // Length of the current token
-        char   code_point[n + 1];
-        strncpy(code_point, str, n);
-        code_point[n] = '\0';  // Make sure it's null-terminated
+        char code_point[n+1];
+        strncpy(code_point, str, n);   // Copy token into buffer
+        code_point[n] = '\0';          // Make sure it's null-terminated
 
         // Normalize the code point: make all hex digits lowercase
         for (char *p = code_point; *p; p++) {
@@ -196,8 +200,10 @@ void send_unicode_hex_string(const char *str) {
     }
 }
 
+// clang-format on
+
 // Borrowed from https://nullprogram.com/blog/2017/10/06/
-const char *decode_utf8(const char *str, int32_t *code_point) {
+static const char *decode_utf8(const char *str, int32_t *code_point) {
     const char *next;
 
     if (str[0] < 0x80) {  // U+0000-007F
@@ -231,7 +237,6 @@ void send_unicode_string(const char *str) {
     }
 
     int32_t code_point = 0;
-
     while (*str) {
         str = decode_utf8(str, &code_point);
 
@@ -243,53 +248,70 @@ void send_unicode_string(const char *str) {
     }
 }
 
+// clang-format off
+
+static void audio_helper(void) {
+#ifdef AUDIO_ENABLE
+    switch (get_unicode_input_mode()) {
+#    ifdef UNICODE_SONG_MAC
+        static float song_mac[][2] = UNICODE_SONG_MAC;
+        case UC_MAC:
+            PLAY_SONG(song_mac);
+            break;
+#    endif
+#    ifdef UNICODE_SONG_LNX
+        static float song_lnx[][2] = UNICODE_SONG_LNX;
+        case UC_LNX:
+            PLAY_SONG(song_lnx);
+            break;
+#    endif
+#    ifdef UNICODE_SONG_WIN
+        static float song_win[][2] = UNICODE_SONG_WIN;
+        case UC_WIN:
+            PLAY_SONG(song_win);
+            break;
+#    endif
+#    ifdef UNICODE_SONG_BSD
+        static float song_bsd[][2] = UNICODE_SONG_BSD;
+        case UC_BSD:
+            PLAY_SONG(song_bsd);
+            break;
+#    endif
+#    ifdef UNICODE_SONG_WINC
+        static float song_winc[][2] = UNICODE_SONG_WINC;
+        case UC_WINC:
+            PLAY_SONG(song_winc);
+            break;
+#    endif
+    }
+#endif
+}
+
+// clang-format on
+
 bool process_unicode_common(uint16_t keycode, keyrecord_t *record) {
     if (record->event.pressed) {
+        bool shifted = get_mods() & MOD_MASK_SHIFT;
         switch (keycode) {
             case UNICODE_MODE_FORWARD:
-                cycle_unicode_input_mode(+1);
+                cycle_unicode_input_mode(shifted ? -1 : +1);
+                audio_helper();
                 break;
             case UNICODE_MODE_REVERSE:
-                cycle_unicode_input_mode(-1);
+                cycle_unicode_input_mode(shifted ? +1 : -1);
+                audio_helper();
                 break;
 
-            case UNICODE_MODE_MAC:
-                set_unicode_input_mode(UC_MAC);
-#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_MAC)
-                static float song_mac[][2] = UNICODE_SONG_MAC;
-                PLAY_SONG(song_mac);
-#endif
-                break;
-            case UNICODE_MODE_LNX:
-                set_unicode_input_mode(UC_LNX);
-#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_LNX)
-                static float song_lnx[][2] = UNICODE_SONG_LNX;
-                PLAY_SONG(song_lnx);
-#endif
-                break;
-            case UNICODE_MODE_WIN:
-                set_unicode_input_mode(UC_WIN);
-#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_WIN)
-                static float song_win[][2] = UNICODE_SONG_WIN;
-                PLAY_SONG(song_win);
-#endif
-                break;
-            case UNICODE_MODE_BSD:
-                set_unicode_input_mode(UC_BSD);
-#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_BSD)
-                static float song_bsd[][2] = UNICODE_SONG_BSD;
-                PLAY_SONG(song_bsd);
-#endif
-                break;
-            case UNICODE_MODE_WINC:
-                set_unicode_input_mode(UC_WINC);
-#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_WINC)
-                static float song_winc[][2] = UNICODE_SONG_WINC;
-                PLAY_SONG(song_winc);
-#endif
+            case UNICODE_MODE_MAC ... UNICODE_MODE_WINC: {
+                // Keycodes and input modes follow the same ordering
+                uint8_t delta = keycode - UNICODE_MODE_MAC;
+                set_unicode_input_mode(UC_MAC + delta);
+                audio_helper();
                 break;
+            }
         }
     }
+
 #if defined(UNICODE_ENABLE)
     return process_unicode(keycode, record);
 #elif defined(UNICODEMAP_ENABLE)
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index 5421c28c7f..4579fde8d5 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -80,7 +80,7 @@ extern uint8_t          unicode_saved_mods;
 void    unicode_input_mode_init(void);
 uint8_t get_unicode_input_mode(void);
 void    set_unicode_input_mode(uint8_t mode);
-void    cycle_unicode_input_mode(uint8_t offset);
+void    cycle_unicode_input_mode(int8_t offset);
 void    persist_unicode_input_mode(void);
 
 void unicode_input_start(void);
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 5445cde129..2f402a2fd2 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -21,7 +21,8 @@ __attribute__((weak)) uint16_t unicodemap_index(uint16_t keycode) {
         // Keycode is a pair: extract index based on Shift / Caps Lock state
         uint16_t index = keycode - QK_UNICODEMAP_PAIR;
 
-        bool shift = unicode_saved_mods & MOD_MASK_SHIFT, caps = IS_HOST_LED_ON(USB_LED_CAPS_LOCK);
+        bool shift = unicode_saved_mods & MOD_MASK_SHIFT;
+        bool caps = IS_HOST_LED_ON(USB_LED_CAPS_LOCK);
         if (shift ^ caps) {
             index >>= 7;
         }