diff --git a/protocols/ssh/include/terminal.h b/protocols/ssh/include/terminal.h index 6dc0bc0c..438e18e1 100644 --- a/protocols/ssh/include/terminal.h +++ b/protocols/ssh/include/terminal.h @@ -204,6 +204,12 @@ struct guac_terminal { */ int selection_end_column; + /** + * Whether the cursor (arrow) keys should send cursor sequences + * or application sequences (DECCKM). + */ + bool application_cursor_keys; + }; /** diff --git a/protocols/ssh/src/guac_handlers.c b/protocols/ssh/src/guac_handlers.c index 60438cdc..673442bd 100644 --- a/protocols/ssh/src/guac_handlers.c +++ b/protocols/ssh/src/guac_handlers.c @@ -298,10 +298,30 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) { else if (keysym == 0xFF1B) { data = "\x1B"; length = 1; } /* Arrow keys */ - else if (keysym == 0xFF52) { data = "\x1B\x5B""A"; length = 3; } - else if (keysym == 0xFF54) { data = "\x1B\x5B""B"; length = 3; } - else if (keysym == 0xFF53) { data = "\x1B\x5B""C"; length = 3; } - else if (keysym == 0xFF51) { data = "\x1B\x5B""D"; length = 3; } + else if (keysym == 0xFF52) { + if (term->application_cursor_keys) data = "\x1BOA"; + else data = "\x1B[A"; + length = 3; + } + + else if (keysym == 0xFF54) { + if (term->application_cursor_keys) data = "\x1BOB"; + else data = "\x1B[B"; + length = 3; + } + + else if (keysym == 0xFF53) { + if (term->application_cursor_keys) data = "\x1BOC"; + else data = "\x1B[C"; + length = 3; + } + + else if (keysym == 0xFF51) { + if (term->application_cursor_keys) data = "\x1BOD"; + else data = "\x1B[D"; + length = 3; + } + /* Ignore other keys */ else return 0; diff --git a/protocols/ssh/src/terminal.c b/protocols/ssh/src/terminal.c index 22374405..1f5b7a4f 100644 --- a/protocols/ssh/src/terminal.c +++ b/protocols/ssh/src/terminal.c @@ -95,6 +95,7 @@ guac_terminal* guac_terminal_create(guac_client* client, term->scroll_end = term->term_height - 1; term->text_selected = false; + term->application_cursor_keys = false; /* Open STDOUT pipe */ if (pipe(term->stdout_pipe_fd)) { diff --git a/protocols/ssh/src/terminal_handlers.c b/protocols/ssh/src/terminal_handlers.c index 5cee5642..f293fe76 100644 --- a/protocols/ssh/src/terminal_handlers.c +++ b/protocols/ssh/src/terminal_handlers.c @@ -284,6 +284,9 @@ int guac_terminal_csi(guac_terminal* term, char c) { static int argc = 0; static int argv[16] = {0}; + /* Whether the sequence started with a question mark */ + static bool initial_question_mark = false; + /* Argument building counter and buffer */ static int argv_length = 0; static char argv_buffer[256]; @@ -553,6 +556,34 @@ int guac_terminal_csi(guac_terminal* term, char c) { term->cursor_row = row; break; + /* h: Set Mode */ + case 'h': + + /* DECCKM */ + if (argv[0] == 1) + term->application_cursor_keys = true; + + else + guac_client_log_info(term->client, + "Unhandled mode set: mode=%i, initial_question_mark=%i", + argv[0], initial_question_mark); + + break; + + /* l: Reset Mode */ + case 'l': + + /* DECCKM */ + if (argv[0] == 1) + term->application_cursor_keys = false; + + else + guac_client_log_info(term->client, + "Unhandled mode reset: mode=%i, initial_question_mark=%i", + argv[0], initial_question_mark); + + break; + /* m: Set graphics rendition */ case 'm': @@ -659,6 +690,9 @@ int guac_terminal_csi(guac_terminal* term, char c) { for (i=0; i