Add remaining keys, fix backspace. Add insert flag.
This commit is contained in:
parent
88ca59a5b3
commit
763ed37179
@ -69,6 +69,11 @@ typedef struct ssh_guac_client_data {
|
|||||||
*/
|
*/
|
||||||
char* clipboard_data;
|
char* clipboard_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the alt key is currently being held down.
|
||||||
|
*/
|
||||||
|
int mod_alt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the control key is currently being held down.
|
* Whether the control key is currently being held down.
|
||||||
*/
|
*/
|
||||||
|
@ -228,6 +228,11 @@ struct guac_terminal {
|
|||||||
*/
|
*/
|
||||||
bool automatic_carriage_return;
|
bool automatic_carriage_return;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether insert mode is enabled (DECIM).
|
||||||
|
*/
|
||||||
|
bool insert_mode;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -352,5 +357,21 @@ void guac_terminal_resize(guac_terminal* term, int width, int height);
|
|||||||
*/
|
*/
|
||||||
void guac_terminal_flush(guac_terminal* terminal);
|
void guac_terminal_flush(guac_terminal* terminal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given string as if typed by the user.
|
||||||
|
*/
|
||||||
|
int guac_terminal_send_data(guac_terminal* term, const char* data, int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given string as if typed by the user.
|
||||||
|
*/
|
||||||
|
int guac_terminal_send_string(guac_terminal* term, const char* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends data through STDIN as if typed by the user, using the format
|
||||||
|
* string given and any args (similar to printf).
|
||||||
|
*/
|
||||||
|
int guac_terminal_sendf(guac_terminal* term, const char* format, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
|||||||
/* Init client data */
|
/* Init client data */
|
||||||
client->data = client_data;
|
client->data = client_data;
|
||||||
client_data->term = term;
|
client_data->term = term;
|
||||||
|
client_data->mod_alt = 0;
|
||||||
client_data->mod_ctrl = 0;
|
client_data->mod_ctrl = 0;
|
||||||
client_data->clipboard_data = NULL;
|
client_data->clipboard_data = NULL;
|
||||||
client_data->term_channel = NULL;
|
client_data->term_channel = NULL;
|
||||||
|
@ -158,7 +158,7 @@ int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) {
|
|||||||
|
|
||||||
int length = strlen(client_data->clipboard_data);
|
int length = strlen(client_data->clipboard_data);
|
||||||
if (length)
|
if (length)
|
||||||
return write(term->stdin_pipe_fd[1],
|
return guac_terminal_send_data(term,
|
||||||
client_data->clipboard_data, length);
|
client_data->clipboard_data, length);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -228,9 +228,6 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
|||||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||||
guac_terminal* term = client_data->term;
|
guac_terminal* term = client_data->term;
|
||||||
|
|
||||||
/* Get write end of STDIN pipe */
|
|
||||||
int fd = term->stdin_pipe_fd[1];
|
|
||||||
|
|
||||||
/* Hide mouse cursor if not already hidden */
|
/* Hide mouse cursor if not already hidden */
|
||||||
if (client_data->current_cursor != client_data->blank_cursor) {
|
if (client_data->current_cursor != client_data->blank_cursor) {
|
||||||
pthread_mutex_lock(&(term->lock));
|
pthread_mutex_lock(&(term->lock));
|
||||||
@ -243,9 +240,10 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Track modifiers */
|
/* Track modifiers */
|
||||||
if (keysym == 0xFFE3) {
|
if (keysym == 0xFFE3)
|
||||||
client_data->mod_ctrl = pressed;
|
client_data->mod_ctrl = pressed;
|
||||||
}
|
else if (keysym == 0xFFE9)
|
||||||
|
client_data->mod_alt = pressed;
|
||||||
|
|
||||||
/* If key pressed */
|
/* If key pressed */
|
||||||
else if (pressed) {
|
else if (pressed) {
|
||||||
@ -257,6 +255,10 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
|||||||
pthread_mutex_unlock(&(term->lock));
|
pthread_mutex_unlock(&(term->lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If alt being held, also send escape character */
|
||||||
|
if (client_data->mod_alt)
|
||||||
|
return guac_terminal_send_string(term, "\x1B");
|
||||||
|
|
||||||
/* Translate Ctrl+letter to control code */
|
/* Translate Ctrl+letter to control code */
|
||||||
if (client_data->mod_ctrl) {
|
if (client_data->mod_ctrl) {
|
||||||
|
|
||||||
@ -272,7 +274,7 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return write(fd, &data, 1);
|
return guac_terminal_send_data(term, &data, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,50 +285,57 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
|||||||
char data[5];
|
char data[5];
|
||||||
|
|
||||||
length = guac_terminal_encode_utf8(keysym & 0xFFFF, data);
|
length = guac_terminal_encode_utf8(keysym & 0xFFFF, data);
|
||||||
return write(fd, data, length);
|
return guac_terminal_send_data(term, data, length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Non-printable keys */
|
||||||
else {
|
else {
|
||||||
|
|
||||||
int length = 0;
|
if (keysym == 0xFF08) return guac_terminal_send_string(term, "\x7F"); /* Backspace */
|
||||||
const char* data = NULL;
|
if (keysym == 0xFF09) return guac_terminal_send_string(term, "\x09"); /* Tab */
|
||||||
|
if (keysym == 0xFF0D) return guac_terminal_send_string(term, "\x0D"); /* Enter */
|
||||||
|
if (keysym == 0xFF1B) return guac_terminal_send_string(term, "\x1B"); /* Esc */
|
||||||
|
|
||||||
if (keysym == 0xFF08) { data = "\x08"; length = 1; }
|
if (keysym == 0xFF50) return guac_terminal_send_string(term, "\x1BOH"); /* Home */
|
||||||
else if (keysym == 0xFF09) { data = "\x09"; length = 1; }
|
|
||||||
else if (keysym == 0xFF0D) { data = "\x0D"; length = 1; }
|
|
||||||
else if (keysym == 0xFF1B) { data = "\x1B"; length = 1; }
|
|
||||||
|
|
||||||
/* Arrow keys */
|
/* Arrow keys w/ application cursor */
|
||||||
else if (keysym == 0xFF52) {
|
if (term->application_cursor_keys) {
|
||||||
if (term->application_cursor_keys) data = "\x1BOA";
|
if (keysym == 0xFF51) return guac_terminal_send_string(term, "\x1BOD"); /* Left */
|
||||||
else data = "\x1B[A";
|
if (keysym == 0xFF52) return guac_terminal_send_string(term, "\x1BOA"); /* Up */
|
||||||
length = 3;
|
if (keysym == 0xFF53) return guac_terminal_send_string(term, "\x1BOC"); /* Right */
|
||||||
|
if (keysym == 0xFF54) return guac_terminal_send_string(term, "\x1BOB"); /* Down */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (keysym == 0xFF51) return guac_terminal_send_string(term, "\x1B[D"); /* Left */
|
||||||
|
if (keysym == 0xFF52) return guac_terminal_send_string(term, "\x1B[A"); /* Up */
|
||||||
|
if (keysym == 0xFF53) return guac_terminal_send_string(term, "\x1B[C"); /* Right */
|
||||||
|
if (keysym == 0xFF54) return guac_terminal_send_string(term, "\x1B[B"); /* Down */
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (keysym == 0xFF54) {
|
if (keysym == 0xFF55) return guac_terminal_send_string(term, "\x1B[5;3~"); /* Page up */
|
||||||
if (term->application_cursor_keys) data = "\x1BOB";
|
if (keysym == 0xFF56) return guac_terminal_send_string(term, "\x1B[6;3~"); /* Page down */
|
||||||
else data = "\x1B[B";
|
if (keysym == 0xFF57) return guac_terminal_send_string(term, "\x1BOF"); /* End */
|
||||||
length = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (keysym == 0xFF53) {
|
if (keysym == 0xFF63) return guac_terminal_send_string(term, "\x1B[2~"); /* Insert */
|
||||||
if (term->application_cursor_keys) data = "\x1BOC";
|
|
||||||
else data = "\x1B[C";
|
|
||||||
length = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (keysym == 0xFF51) {
|
if (keysym == 0xFFBE) return guac_terminal_send_string(term, "\x1BOP"); /* F1 */
|
||||||
if (term->application_cursor_keys) data = "\x1BOD";
|
if (keysym == 0xFFBF) return guac_terminal_send_string(term, "\x1BOQ"); /* F2 */
|
||||||
else data = "\x1B[D";
|
if (keysym == 0xFFC0) return guac_terminal_send_string(term, "\x1BOR"); /* F3 */
|
||||||
length = 3;
|
if (keysym == 0xFFC1) return guac_terminal_send_string(term, "\x1BOS"); /* F4 */
|
||||||
}
|
|
||||||
|
|
||||||
|
if (keysym == 0xFFC2) return guac_terminal_send_string(term, "\x1B[15~"); /* F5 */
|
||||||
|
if (keysym == 0xFFC3) return guac_terminal_send_string(term, "\x1B[17~"); /* F6 */
|
||||||
|
if (keysym == 0xFFC4) return guac_terminal_send_string(term, "\x1B[18~"); /* F7 */
|
||||||
|
if (keysym == 0xFFC5) return guac_terminal_send_string(term, "\x1B[19~"); /* F8 */
|
||||||
|
if (keysym == 0xFFC6) return guac_terminal_send_string(term, "\x1B[20~"); /* F9 */
|
||||||
|
if (keysym == 0xFFC7) return guac_terminal_send_string(term, "\x1B[21~"); /* F10 */
|
||||||
|
if (keysym == 0xFFC8) return guac_terminal_send_string(term, "\x1B[22~"); /* F11 */
|
||||||
|
if (keysym == 0xFFC9) return guac_terminal_send_string(term, "\x1B[23~"); /* F12 */
|
||||||
|
|
||||||
/* Ignore other keys */
|
if (keysym == 0xFFFF) return guac_terminal_send_string(term, "\x1B[3~"); /* Delete */
|
||||||
else return 0;
|
|
||||||
|
|
||||||
return write(fd, data, length);
|
/* Ignore unknown keys */
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ void guac_terminal_reset(guac_terminal* term) {
|
|||||||
term->text_selected = false;
|
term->text_selected = false;
|
||||||
term->application_cursor_keys = false;
|
term->application_cursor_keys = false;
|
||||||
term->automatic_carriage_return = false;
|
term->automatic_carriage_return = false;
|
||||||
|
term->insert_mode = false;
|
||||||
|
|
||||||
/* Clear terminal */
|
/* Clear terminal */
|
||||||
for (row=0; row<term->term_height; row++)
|
for (row=0; row<term->term_height; row++)
|
||||||
@ -755,3 +757,32 @@ void guac_terminal_resize(guac_terminal* term, int width, int height) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_terminal_send_data(guac_terminal* term, const char* data, int length) {
|
||||||
|
return guac_terminal_write_all(term->stdin_pipe_fd[1], data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_terminal_send_string(guac_terminal* term, const char* data) {
|
||||||
|
return guac_terminal_write_all(term->stdin_pipe_fd[1], data, strlen(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_terminal_sendf(guac_terminal* term, const char* format, ...) {
|
||||||
|
|
||||||
|
int written;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
/* Print to buffer */
|
||||||
|
va_start(ap, format);
|
||||||
|
written = vsnprintf(buffer, sizeof(buffer)-1, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (written < 0)
|
||||||
|
return written;
|
||||||
|
|
||||||
|
/* Write to STDIN */
|
||||||
|
return guac_terminal_write_all(term->stdin_pipe_fd[1], buffer, written);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
@ -58,31 +57,6 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_TERMINAL_OK "\x1B[0n"
|
#define GUAC_TERMINAL_OK "\x1B[0n"
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends data through STDIN as if typed by the user, using the format
|
|
||||||
* string given and any args (similar to printf).
|
|
||||||
*/
|
|
||||||
static int guac_terminal_respond(guac_terminal* term, const char* format, ...) {
|
|
||||||
|
|
||||||
int written;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
char buffer[1024];
|
|
||||||
|
|
||||||
/* Print to buffer */
|
|
||||||
va_start(ap, format);
|
|
||||||
written = vsnprintf(buffer, sizeof(buffer)-1, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (written < 0)
|
|
||||||
return written;
|
|
||||||
|
|
||||||
/* Write to STDIN */
|
|
||||||
return guac_terminal_write_all(term->stdin_pipe_fd[1], buffer, written);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int guac_terminal_echo(guac_terminal* term, char c) {
|
int guac_terminal_echo(guac_terminal* term, char c) {
|
||||||
|
|
||||||
static int bytes_remaining = 0;
|
static int bytes_remaining = 0;
|
||||||
@ -140,7 +114,7 @@ int guac_terminal_echo(guac_terminal* term, char c) {
|
|||||||
|
|
||||||
/* Enquiry */
|
/* Enquiry */
|
||||||
case 0x05:
|
case 0x05:
|
||||||
guac_terminal_respond(term, "%s", GUAC_TERMINAL_ANSWERBACK);
|
guac_terminal_send_string(term, GUAC_TERMINAL_ANSWERBACK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Bell */
|
/* Bell */
|
||||||
@ -345,7 +319,7 @@ int guac_terminal_escape(guac_terminal* term, char c) {
|
|||||||
|
|
||||||
/* DEC Identify */
|
/* DEC Identify */
|
||||||
case 'Z':
|
case 'Z':
|
||||||
guac_terminal_respond(term, "%s", GUAC_TERMINAL_VT102_ID);
|
guac_terminal_send_string(term, GUAC_TERMINAL_VT102_ID);
|
||||||
term->char_handler = guac_terminal_echo;
|
term->char_handler = guac_terminal_echo;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -413,6 +387,7 @@ static bool* __guac_terminal_get_flag(guac_terminal* term, int num, char private
|
|||||||
|
|
||||||
else if (private_mode == 0) {
|
else if (private_mode == 0) {
|
||||||
switch (num) {
|
switch (num) {
|
||||||
|
case 4: return &(term->insert_mode); /* DECIM */
|
||||||
case 20: return &(term->automatic_carriage_return); /* LF/NL */
|
case 20: return &(term->automatic_carriage_return); /* LF/NL */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,7 +671,7 @@ int guac_terminal_csi(guac_terminal* term, char c) {
|
|||||||
/* c: Identify */
|
/* c: Identify */
|
||||||
case 'c':
|
case 'c':
|
||||||
if (argv[0] == 0 && private_mode_character == 0)
|
if (argv[0] == 0 && private_mode_character == 0)
|
||||||
guac_terminal_respond(term, "%s", GUAC_TERMINAL_VT102_ID);
|
guac_terminal_send_string(term, GUAC_TERMINAL_VT102_ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* d: Move cursor, current col */
|
/* d: Move cursor, current col */
|
||||||
@ -810,11 +785,11 @@ int guac_terminal_csi(guac_terminal* term, char c) {
|
|||||||
|
|
||||||
/* Device status report */
|
/* Device status report */
|
||||||
if (argv[0] == 5 && private_mode_character == 0)
|
if (argv[0] == 5 && private_mode_character == 0)
|
||||||
guac_terminal_respond(term, "%s", GUAC_TERMINAL_OK);
|
guac_terminal_send_string(term, GUAC_TERMINAL_OK);
|
||||||
|
|
||||||
/* Cursor position report */
|
/* Cursor position report */
|
||||||
else if (argv[0] == 6 && private_mode_character == 0)
|
else if (argv[0] == 6 && private_mode_character == 0)
|
||||||
guac_terminal_respond(term, "\x1B[%i;%iR", term->cursor_row+1, term->cursor_col+1);
|
guac_terminal_sendf(term, "\x1B[%i;%iR", term->cursor_row+1, term->cursor_col+1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user