orange-guo created GUACAMOLE-2091: ------------------------------------- Summary: Double-width Characters Rendering Problem (First Character Missing/Corrupted) when Pasting from Clipboard in SSH Terminal Key: GUACAMOLE-2091 URL: https://issues.apache.org/jira/browse/GUACAMOLE-2091 Project: Guacamole Issue Type: Bug Components: guacamole-server Affects Versions: 1.6.0 Reporter: orange-guo Attachments: image-2025-06-30-10-03-00-698.png, image-2025-06-30-10-04-04-535.png
*Problem Description:* When pasting text containing Chinese characters from the clipboard into a Guacamole SSH terminal session, the very first Chinese character of the pasted text fails to render correctly (appears missing). Subsequent characters within the same pasted text, render correctly. !image-2025-06-30-10-04-04-535.png! *Steps to Reproduce:* * Connect to a remote machine via a SSH protocol. * Copy a string of Chinese characters (e.g., "我是人") from your local machine's clipboard. * Paste the copied text into the Guacamole terminal session. * Observe the terminal display: the first Chinese character (e.g., "我") is not visible or is corrupted, while "是人" appears correctly. *Example Debug Logs (before fix, pasting "我是人" starting at `col=26`):* {code:java} guacd[...]: DEBUG: echo: Codepoint ready for processing: 0x6211 ('我') guacd[...]: DEBUG: echo: Calling guac_terminal_set for char 0x6211 at (39,26). 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 # <--- This line caused the issue 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. # ... (other characters '是', '人' processing - these were fine) ... guacd[...]: DEBUG: display_set_columns: row=39, input_start_col=26, input_end_col=26, char_codepoint=0x20 (' '), char_width=1 # <--- Final overwrite 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. {code} ** *Root Cause Analysis* The root cause lies in how terminal display logic handles *double-width characters* (like Chinese) when they overlap with the cursor, leading to inconsistent updates and eventual overwrites in the display buffer. {*}Proposed Solution:{*}{*}{*} The problem can be resolved by ensuring that the cursor redraw logic within *guac_*{*}terminal_set_columns{*} correctly accounts for the full width of multi-column characters. This ensures that the character's state in the display buffer remains consistent throughout all operations. File: terminal.c Function: guac_terminal_set_columns{*}{*} {code:java} 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; // Correctly calculate the redraw range to cover the entire character width int cursor_redraw_start_col = terminal->visible_cursor_col; int cursor_redraw_end_col = terminal->visible_cursor_col + character->width - 1; // Ensure redraw range does not exceed the original set bounds 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; // Re-submit the character with cursor attributes, covering its full width __guac_terminal_set_columns(terminal, row, cursor_redraw_start_col, cursor_redraw_end_col, &cursor_character); } } {code} I can create a pull request on Github to fix this issue later, if needed. Here is the screen screenshot after the problem was fixed !https://git.fastonetech.com:8443/-/project/401/uploads/fe322ac1b7eea72bb5ccb8b0a3a0c1ef/image.png! -- This message was sent by Atlassian Jira (v8.20.10#820010)