[ 
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)

Reply via email to