Skip to content
Go back

将Apache Guacamole从1.5.5升级到1.6.0版本后SSH终端粘贴中文首个字符不显示问题排查与解决

Edit page

Apache Guacamole1.5.5升级到1.6.0版本后SSH终端粘贴中文首个字符不显示问题排查与解决

在将Apache Guacamole1.5.5升级到1.6.0版本后,遇到了一个的问题: 在使用SSH终端时,粘贴中文文本的第一个字符无法正常显示。

从本地复制一段以中文字符开头的文本(例如:“我是人”)并粘贴到Guacamole终端中时,屏幕上显示的并非完整的我是人,而是是人,开头的字不翼而飞。

cfb396cc38020b333834ea53436e0ba7116734666aeeaa7766b031579fe28de0.png

经过一番排查和测试,最终找到了问题的根源并给出了解决方案。

日志信息

guacd内部的渲染流程入手,开启了详细的Debug日志。 当粘贴“我”字时,捕获到以下核心日志片段:

guacd[...]: DEBUG:    Rendering char: row=39, col=26, codepoint=0x6211 ('我'), width=2
guacd[...]: DEBUG:    set_columns: Primary set for row=39, cols=[26,27], char=0x6211('我'), width=2
guacd[...]: DEBUG:    display_set_columns: row=39, input_start_col=26, input_end_col=27, char_codepoint=0x6211 ('我'), char_width=2
guacd[...]: DEBUG:    display_set_columns: Starting loop to set columns from 26 to 27 (char_width=2).
guacd[...]: DEBUG:    display_set_columns: Processing col 26, current_op_type=0 (GUAC_CHAR_COPY=1)
guacd[...]: DEBUG:    display_set_columns: Set op for col 26: type=2, char_codepoint=0x6211.
guacd[...]: DEBUG:    display_set_columns: Marking unflushed_set for row 39.
guacd[...]: DEBUG:    set_columns: Cursor detected at row=39, col=26. Character width is 2.
guacd[...]: DEBUG:    set_columns: Redrawing cursor char. Original visible_cursor_col=26. Adjusted redraw range: [26,27].
guacd[...]: DEBUG:    display_set_columns: row=39, input_start_col=26, input_end_col=26, char_codepoint=0x6211 ('我'), char_width=2  # <-- 第一次异常覆盖点
guacd[...]: DEBUG:    display_set_columns: Starting loop to set columns from 26 to 26 (char_width=2).
guacd[...]: DEBUG:    display_set_columns: Processing col 26, current_op_type=2 (GUAC_CHAR_COPY=1)
guacd[...]: DEBUG:    display_set_columns: Set op for col 26: type=2, char_codepoint=0x6211.
guacd[...]: DEBUG:    display_set_columns: Marking unflushed_set for row 39.
# ... (其他字符正常处理) ...
guacd[...]: DEBUG:    display_set_columns: row=39, input_start_col=26, input_end_col=26, char_codepoint=0x20 (' '), char_width=1 # <-- 最终致命覆盖
guacd[...]: DEBUG:    display_set_columns: Starting loop to set columns from 26 to 26 (char_width=1).
guacd[...]: DEBUG:    display_set_columns: Processing col 26, current_op_type=2 (GUAC_CHAR_COPY=1)
guacd[...]: DEBUG:    display_set_columns: Set op for col 26: type=2, char_codepoint=0x20.
guacd[...]: DEBUG:    display_set_columns: Marking unflushed_set for row 39.

以上日志揭示的核心问题链条:

字初次设置是正确的: guac_terminal_set 初次调用set_columns时,传入的范围 [26,27] (宽度为2) 是符合中文显示需求的。 光标重绘的“副作用”: 当光标恰好位于这个字符的起始列 (col=26) 时,set_columns 内部的光标重绘逻辑被触发。 然而,此处再次调用 display_set_columns 时,传入的 input_end_col=26 变成了单列范围,导致对双宽字符的不完整覆盖。

问题原因

双宽字符操作的“错位”, 问题的根本在于 Guacamole 终端在处理双宽度字符(如中文,占用两列显示空间)时,其内部状态管理和重绘机制中的“错位写入”和“不完全覆盖”缺陷。

这些缺陷导致了显示缓冲区中字符状态的混淆和相互覆盖,最终表现为中文首字无法正常显示。

解决方案

问题定位到 src/terminal/terminal.c 文件中的guac_terminal_set_columns函数。我们需要修正其内部光标重绘逻辑,确保在处理双宽度字符时,始终以其完整的显示宽度来更新显示缓冲区。

修改后的guac_terminal_set_columns代码:

void guac_terminal_set_columns(guac_terminal* terminal, int row, int start_column, int end_column, guac_terminal_char* character) {

    // Primary set for the character
    // 第一次将字符写入缓冲区,确保是完整两列
    __guac_terminal_set_columns(terminal, row, start_column, end_column, character);

    /* If visible cursor in current row, preserve state */
    // 如果光标在当前行,并且其位置与当前设置的字符区域重叠
    if (row == terminal->visible_cursor_row
            && terminal->visible_cursor_col >= start_column
            && terminal->visible_cursor_col <= end_column) {

        guac_terminal_char cursor_character = *character;
        cursor_character.attributes.cursor = true;

        // 【核心修复】计算实际需要重绘的起始列和结束列,以覆盖整个字符的宽度
        int cursor_redraw_start_col = terminal->visible_cursor_col;
        int cursor_redraw_end_col = terminal->visible_cursor_col + character->width - 1;

        // 确保重绘范围不会超出原始的设置范围 (安全边界)
        if (cursor_redraw_start_col < start_column)
            cursor_redraw_start_col = start_column;
        if (cursor_redraw_end_col > end_column)
            cursor_redraw_end_col = end_column;

        // 重新提交字符,这次要确保带有光标属性的字符覆盖其完整的两列
        __guac_terminal_set_columns(terminal, row,
                                    cursor_redraw_start_col,
                                    cursor_redraw_end_col,
                                    &cursor_character);
    }
}

这段修改确保了所有对双宽度字符的SET操作(无论是初次放置还是光标重绘)都能够正确地处理其完整宽度。 消除了显示缓冲区中的不一致状态,避免了后续的错误覆盖。

经测试,中文首字渲染问题得以解决,字符能够正常显示。

90a58c10166073ac640466ef4bee4a7ba4350970690cdf38a6a22c74d02240f8.png

参考资料


Edit page
Share this post on:

Previous Post
解决 Spring Boot 3.5.0 后 Jasypt 无法解析环境变量中的加密字符串问题
Next Post
创建VNC会话报错A VNC server is already running as :xxx