Commit 4bdca4c7 for guacamole.apache.org

commit 4bdca4c7639e0ccc97dfbe2fe2cfc40b9ba1ced5
Author: Michael Jumper <mjumper@apache.org>
Date:   Mon Aug 3 17:30:22 2026 -0700

    GUACAMOLE-2313: Do not scroll the terminal to the bottom for modifier keys.

diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index d9805689..3628e4f5 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -121,18 +121,23 @@ typedef enum guac_terminal_keysym {
     GUAC_KEYSYM_SHIFT_R = 0xFFE2,           /* Right Shift modifier key.                   */
     GUAC_KEYSYM_CTRL_L = 0xFFE3,            /* Left Control modifier key.                  */
     GUAC_KEYSYM_CTRL_R = 0xFFE4,            /* Right Control modifier key.                 */
-    GUAC_KEYSYM_META_L = 0xFFE7,            /* Left Meta modifier key.                     */
-    GUAC_KEYSYM_META_R = 0xFFE8,            /* Right Meta modifier key.                    */
+    GUAC_KEYSYM_COMMAND_L = 0xFFE7,         /* Left Command key (Mac-specific).            */
+    GUAC_KEYSYM_COMMAND_R = 0xFFE8,         /* Right Command key (Mac-specific).           */
     GUAC_KEYSYM_ALT_L = 0xFFE9,             /* Left Alt modifier key.                      */
     GUAC_KEYSYM_ALT_R = 0xFFEA,             /* Right Alt modifier key.                     */
-    GUAC_KEYSYM_SUPER_L = 0xFFEB,           /* Left Super key, such as Windows/Command.    */
-    GUAC_KEYSYM_SUPER_R = 0xFFEC,           /* Right Super key, such as Windows/Command.   */
-    GUAC_KEYSYM_HYPER_L = 0xFFED,           /* Left Hyper modifier key.                    */
-    GUAC_KEYSYM_HYPER_R = 0xFFEE,           /* Right Hyper modifier key.                   */
+    GUAC_KEYSYM_SUPER_L = 0xFFEB,           /* Left Super key ("OS" or "Windows" key).     */
+    GUAC_KEYSYM_SUPER_R = 0xFFEC,           /* Right Super key ("OS" or "Windows" key).    */
+    GUAC_KEYSYM_OPTION_L = 0xFFED,          /* Left Option key (Mac-specific).             */
+    GUAC_KEYSYM_OPTION_R = 0xFFEE,          /* Right Option key (Mac-specific).            */
     GUAC_KEYSYM_MODE_SWITCH = 0xFF7E,       /* Keyboard group or layout switch key.        */
-    GUAC_KEYSYM_ISO_LEVEL3_SHIFT = 0xFE03,  /* ISO Level 3 shift key, often AltGr/Option.  */
+    GUAC_KEYSYM_ALTGR = 0xFE03,             /* ISO Level 3 shift key (AltGr)               */
     GUAC_KEYSYM_ISO_LEVEL5_SHIFT = 0xFE11,  /* ISO Level 5 shift key.                      */

+    /* Lock keys */
+    GUAC_KEYSYM_CAPS_LOCK = 0xFFE5,         /* Caps Lock key.                              */
+    GUAC_KEYSYM_NUM_LOCK = 0xFF7F,          /* Num Lock key.                               */
+    GUAC_KEYSYM_SCROLL_LOCK = 0xFF14,       /* Scroll Lock key.                            */
+
     /* Arrow/navigation direction keys */
     GUAC_KEYSYM_LEFT = 0xFF51,              /* Left arrow key.                             */
     GUAC_KEYSYM_UP = 0xFF52,                /* Up arrow key.                               */
@@ -1633,6 +1638,35 @@ static int __guac_terminal_is_editing_keysym(int keysym) {
         || keysym == GUAC_KEYSYM_PAGE_DOWN || keysym == GUAC_KEYSYM_KP_PAGE_DOWN;
 }

+/**
+ * Returns whether the given keysym is a modifier.
+ *
+ * @param keysym
+ *     The X11 keysym to test.
+ *
+ * @return
+ *     Non-zero if the keysym is a modifier, zero otherwise.
+ */
+static int __guac_terminal_is_modifier_keysym(int keysym) {
+    return (keysym >= GUAC_KEYSYM_SHIFT_L && keysym <= GUAC_KEYSYM_OPTION_R)
+        || keysym == GUAC_KEYSYM_ALTGR;
+}
+
+/**
+ * Returns whether the given keysym is a lock key.
+ *
+ * @param keysym
+ *     The X11 keysym to test.
+ *
+ * @return
+ *     Non-zero if the keysym is a lock key, zero otherwise.
+ */
+static int __guac_terminal_is_lock_keysym(int keysym) {
+    return keysym == GUAC_KEYSYM_CAPS_LOCK
+        || keysym == GUAC_KEYSYM_NUM_LOCK
+        || keysym == GUAC_KEYSYM_SCROLL_LOCK;
+}
+
 /**
  * Returns the xterm-style modifier parameter for CSI key sequences, encoding
  * the current modifier state of the terminal. The value is 1 plus the bitmask
@@ -1810,19 +1844,18 @@ static int __guac_terminal_send_key(guac_terminal* term, int keysym, int pressed
     }

     /*
-     * Super (Windows/Command) and Hyper are treated as Meta since terminals don't
-     * have separate modifier bits for them.
+     * Super (the "Windows" key) and Command are treated as Meta since
+     * terminals don't have separate modifier bits for them.
      *
-     * MODE_SWITCH and the ISO level selectors are intentionally not treated as
-     * Alt. On international layouts these are often used to produce printable
-     * third-/fifth-level characters, and folding them into Alt would inject an
-     * unwanted ESC prefix into normal text input.
+     * Option and AltGr are intentionally not treated as terminal-visible
+     * modifiers. These keys are used purely to compose printable characters
+     * and treating them as a modifiers would add unwanted console code
+     * sequences into otherwise normal text, breaking input.
      */
     if (keysym == GUAC_KEYSYM_CTRL_L || keysym == GUAC_KEYSYM_CTRL_R)
         term->mod_ctrl = pressed;
-    else if (keysym == GUAC_KEYSYM_META_L || keysym == GUAC_KEYSYM_META_R
-            || keysym == GUAC_KEYSYM_SUPER_L || keysym == GUAC_KEYSYM_SUPER_R
-            || keysym == GUAC_KEYSYM_HYPER_L || keysym == GUAC_KEYSYM_HYPER_R)
+    else if (keysym == GUAC_KEYSYM_COMMAND_L || keysym == GUAC_KEYSYM_COMMAND_R
+            || keysym == GUAC_KEYSYM_SUPER_L || keysym == GUAC_KEYSYM_SUPER_R)
         term->mod_meta = pressed;
     else if (keysym == GUAC_KEYSYM_ALT_L || keysym == GUAC_KEYSYM_ALT_R)
         term->mod_alt = pressed;
@@ -1867,9 +1900,12 @@ static int __guac_terminal_send_key(guac_terminal* term, int keysym, int pressed

         }

-        /* Reset scroll */
-        if (term->scroll_offset != 0)
+        /* Reset scroll, unless the pressed key produces no output (ie: is purely
+         * a modifier or lock key) */
+        if (term->scroll_offset != 0 && !__guac_terminal_is_modifier_keysym(keysym)
+                && !__guac_terminal_is_lock_keysym(keysym)) {
             guac_terminal_scroll_display_down(term, term->scroll_offset);
+        }

         /*
          * Modified arrows, function keys, and cursor editing keys encode Alt