[ https://issues.apache.org/jira/browse/GUACAMOLE-2091?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
orange-guo updated GUACAMOLE-2091: ---------------------------------- Description: *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 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! was: *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! > 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 > Priority: Major > 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 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)