Skip to content

Commit

Permalink
GUACAMOLE-192: Select word in terminal on double click
Browse files Browse the repository at this point in the history
  • Loading branch information
corentin-soriano committed Apr 15, 2024
1 parent 633d5b9 commit 73e0167
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/terminal/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ void guac_terminal_select_update(guac_terminal* terminal, int row, int column) {

/* Only update if selection has changed */
if (row != terminal->selection_end_row
|| column < terminal->selection_end_column
|| column <= terminal->selection_end_column
|| column >= terminal->selection_end_column + terminal->selection_end_width) {

int width = guac_terminal_find_char(terminal, row, &column);
Expand Down
105 changes: 103 additions & 2 deletions src/terminal/terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,10 @@ guac_terminal* guac_terminal_create(guac_client* client,
/* Configure backspace */
term->backspace = options->backspace;

/* Initialize mouse latest click time and counter */
term->click_timer = 0;
term->click_counter = 0;

return term;

}
Expand Down Expand Up @@ -1809,8 +1813,34 @@ static int __guac_terminal_send_mouse(guac_terminal* term, guac_user* user,
if (pressed_mask & GUAC_CLIENT_MOUSE_LEFT) {
if (term->mod_shift)
guac_terminal_select_resume(term, row, col);
else
guac_terminal_select_start(term, row, col);
else {

/* Reset click counter if last click was 300ms before */
if (guac_timestamp_current() - term->click_timer > 300)
term->click_counter = 0;

/* New click time */
term->click_timer = guac_timestamp_current();

switch (term->click_counter++) {

/* First click = start selection */
case 0:
guac_terminal_select_start(term, row, col);
break;

/* Second click = word selection */
case 1:
guac_terminal_double_click(term, row, col);
break;

/* third click or more = line selection */
default:
guac_terminal_select_start(term, row, 0);
guac_terminal_select_update(term, row, term->display->width);
break;
}
}
}

/* In all other cases, simply update the existing selection as long as
Expand Down Expand Up @@ -2224,3 +2254,74 @@ void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user) {
/* Remove the user from the terminal cursor */
guac_common_cursor_remove_user(terminal->cursor, user);
}

bool guac_terminal_is_part_of_word(int ascii_char) {
if ((ascii_char >= '0' && ascii_char <= '9') ||
(ascii_char >= 'A' && ascii_char <= 'Z') ||
(ascii_char >= 'a' && ascii_char <= 'z') ||
(ascii_char == '$') ||
(ascii_char == '%') ||
(ascii_char == '&') ||
(ascii_char == '-') ||
(ascii_char == '.') ||
(ascii_char == '/') ||
(ascii_char == ':') ||
(ascii_char == '=') ||
(ascii_char == '?') ||
(ascii_char == '\\') ||
(ascii_char == '_') ||
(ascii_char == '~'))
return true;
else
return false;
}

bool guac_terminal_is_blank(int ascii_char) {
if (ascii_char == '\0' || ascii_char == ' ')
return true;
else
return false;
}

void guac_terminal_double_click(guac_terminal* terminal, int row, int col) {

/* Read char at his real position when scrolling */
int scrolled_row = row + terminal->scroll_offset;
/* (char)10 behind cursor */
int cursor_char = terminal->display->operations[scrolled_row * terminal->display->width + col].character.value;
/* Position of the word behind cursor.
* Default = col required to select a char if not a word and not blank.
*/
int word_head = col;
int word_tail = col;
int flag;
/* The function used to calculate the word borders */
bool (*word_border)(int) = NULL;

/* If selection is on a word, get its borders */
if (guac_terminal_is_part_of_word(cursor_char))
word_border = guac_terminal_is_part_of_word;

/* If selection is on a blank, get its borders */
else if (guac_terminal_is_blank(cursor_char))
word_border = guac_terminal_is_blank;

if (word_border != NULL) {
/* Get word head*/
do {
flag = terminal->display->operations[scrolled_row * terminal->display->width + (word_head-1)].character.value;
} while (word_border(flag) && (word_head >= 0 && word_head <= terminal->display->width) && word_head--);

/* Get word tail */
do {
flag = terminal->display->operations[scrolled_row * terminal->display->width + (word_tail+1)].character.value;
} while (word_border(flag) && (word_tail >= 0 && word_tail <= terminal->display->width) && word_tail++);
}

/* Select and add to clipboard the "word" */
guac_terminal_select_start(terminal, row, word_head);
guac_terminal_select_update(terminal, row, word_tail);

return;

}
27 changes: 27 additions & 0 deletions src/terminal/terminal/terminal-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,16 @@ struct guac_terminal {
*/
bool disable_copy;

/**
* The time betwen two left clicks.
*/
guac_timestamp click_timer;

/**
* Counter for left clicks :
*/
int click_counter;

};

/**
Expand Down Expand Up @@ -656,5 +666,22 @@ void guac_terminal_copy_rows(guac_terminal* terminal,
*/
void guac_terminal_flush(guac_terminal* terminal);

/**
* Determination of part of word
* Match like this pattern : [0-9\/A-Za-z_\~\&\-\.\?\\]
*/
bool guac_terminal_is_part_of_word(int ascii_char);

/**
* Determination of blank
* Match like this pattern : [\0\ ]
*/
bool guac_terminal_is_blank(int ascii_char);

/**
* Selection on double click event
*/
void guac_terminal_double_click(guac_terminal* terminal, int row, int col);

#endif

0 comments on commit 73e0167

Please sign in to comment.