diff --git a/README.md b/README.md index 76a7ef6..f084d0e 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Options: --line-pulse-duration Set line pulse duration -n, --no-autoconnect Disable automatic connect -e, --local-echo Enable local echo - --input-mode normal|hex Select input mode (default: normal) + --input-mode normal|hex|line Select input mode (default: normal) --output-mode normal|hex Select output mode (default: normal) -t, --timestamp Enable line timestamp --timestamp-format Set timestamp format (default: 24hour) diff --git a/TODO b/TODO index 9fc3626..e00f76b 100644 --- a/TODO +++ b/TODO @@ -26,10 +26,11 @@ Time is in ms. -* Line mode feature +* Advanced line mode - Only send line when pressing enter. Maybe even add readline support so one - can use all the readline editing feature before sending the line. + Current line mode only support backspace editing. Would be nice with arrow + key navigation left/right and insert/overwrite support. Also history browsing + pressing up/down. * Support for interaction using simple autoresponse strings diff --git a/man/tio.1.in b/man/tio.1.in index 875a881..17871f1 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -191,11 +191,18 @@ If defining more than one flag, the flags must be comma separated. .RE .TP -.BR " \-\-input\-mode " normal|hex +.BR " \-\-input\-mode " normal|hex|line -Set input mode. In hex input mode bytes can be sent by typing the -\fBtwo-character hexadecimal\fR representation of the 1 byte value, e.g.: to -send \fI0xA\fR you must type \fI0a\fR or \fI0A\fR. +Set input mode. + +In normal mode input characters are sent immediately as they are typed. + +In hex input mode bytes can be sent by typing the \fBtwo-character +hexadecimal\fR representation of the 1 byte value, e.g.: to send \fI0xA\fR you +must type \fI0a\fR or \fI0A\fR. + +In line input mode input characters are sent when you press enter. The only +editing feature supported in this mode is backspace. Default value is "normal". diff --git a/src/bash-completion/tio.in b/src/bash-completion/tio.in index 10bf6ef..efe9617 100644 --- a/src/bash-completion/tio.in +++ b/src/bash-completion/tio.in @@ -131,7 +131,7 @@ _tio() return 0 ;; --input-mode) - COMPREPLY=( $(compgen -W "normal hex" -- ${cur}) ) + COMPREPLY=( $(compgen -W "normal hex line" -- ${cur}) ) return 0 ;; --output-mode) diff --git a/src/options.c b/src/options.c index feef128..d231cc7 100644 --- a/src/options.c +++ b/src/options.c @@ -126,7 +126,7 @@ void print_help(char *argv[]) printf(" --line-pulse-duration Set line pulse duration\n"); printf(" -n, --no-autoconnect Disable automatic connect\n"); printf(" -e, --local-echo Enable local echo\n"); - printf(" --input-mode normal|hex Select input mode (default: normal)\n"); + printf(" --input-mode normal|hex|line Select input mode (default: normal)\n"); printf(" --output-mode normal|hex Select output mode (default: normal)\n"); printf(" -t, --timestamp Enable line timestamp\n"); printf(" --timestamp-format Set timestamp format (default: 24hour)\n"); @@ -226,6 +226,10 @@ input_mode_t input_mode_option_parse(const char *arg) { return INPUT_MODE_HEX; } + else if (strcmp("line", arg) == 0) + { + return INPUT_MODE_LINE; + } else { tio_error_printf("Invalid input mode option"); @@ -258,6 +262,8 @@ const char *input_mode_by_string(input_mode_t mode) return "normal"; case INPUT_MODE_HEX: return "hex"; + case INPUT_MODE_LINE: + return "line"; case INPUT_MODE_END: break; } diff --git a/src/options.h b/src/options.h index 7a6b627..aff99fc 100644 --- a/src/options.h +++ b/src/options.h @@ -34,6 +34,7 @@ typedef enum { INPUT_MODE_NORMAL, INPUT_MODE_HEX, + INPUT_MODE_LINE, INPUT_MODE_END, } input_mode_t; diff --git a/src/print.c b/src/print.c index 1c891aa..04d17da 100644 --- a/src/print.c +++ b/src/print.c @@ -31,11 +31,13 @@ char ansi_format[30]; void print_hex(char c) { + print_tainted = true; printf("%02x ", (unsigned char) c); } void print_normal(char c) { + print_tainted = true; putchar(c); } diff --git a/src/tty.c b/src/tty.c index 84c5b91..d43acf3 100644 --- a/src/tty.c +++ b/src/tty.c @@ -195,8 +195,6 @@ static void optional_local_echo(char c) { log_putc(c); } - - print_tainted_set(); } inline static bool is_valid_hex(char c) @@ -887,6 +885,11 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) tio_printf("Switched to hex input mode"); break; + case INPUT_MODE_LINE: + option.input_mode = INPUT_MODE_LINE; + tio_printf("Switched to line input mode"); + break; + case INPUT_MODE_END: option.input_mode = INPUT_MODE_NORMAL; tio_printf("Switched to normal input mode"); @@ -1531,11 +1534,14 @@ int tty_connect(void) fd_set rdfs; /* Read file descriptor set */ int maxfd; /* Maximum file descriptor used */ char input_char, output_char; - char input_buffer[BUFSIZ]; + char input_buffer[BUFSIZ] = {}; + char line_buffer[BUFSIZ] = {}; static bool first = true; int status; bool next_timestamp = false; char* now = NULL; + unsigned int line_index = 0; + static char previous_char[2] = {}; /* Open tty device */ device_fd = open(option.tty_device, O_RDWR | O_NOCTTY | O_NONBLOCK); @@ -1805,12 +1811,107 @@ int tty_connect(void) /* Handle commands */ handle_command_sequence(input_char, &output_char, &forward); - if ((option.input_mode == INPUT_MODE_HEX) && (forward)) + if (forward) { - if (!is_valid_hex(input_char)) + switch (option.input_mode) { - tio_warning_printf("Invalid hex character: '%d' (0x%02x)", input_char, input_char); - forward = false; + case INPUT_MODE_HEX: + if (!is_valid_hex(input_char)) + { + tio_warning_printf("Invalid hex character: '%d' (0x%02x)", input_char, input_char); + forward = false; + } + break; + + case INPUT_MODE_LINE: + switch (input_char) + { + case 27: // Escape + forward = false; + break; + + case '[': + if (previous_char[0] == 27) + { + forward = false; + } + break; + + case 'A': + case 'B': + case 'C': + case 'D': + if ((previous_char[1] == 27) && (previous_char[0] == '[')) + { + // Handle arrow keys + switch (input_char) + { + case 'A': // Up arrow + // Ignore + break; + case 'B': // Down arrow + // Ignore + break; + case 'C': // Right arrow + // Ignore + break; + case 'D': // Left arrow + // Ignore + break; + } + forward = false; + } + break; + + case '\b': + case 127: // Backspace + if (line_index) + { + if ((option.output_mode == OUTPUT_MODE_HEX) && (option.local_echo)) + { + printf("\b\b\b \b\b\b"); // Destructive backspace + } + else + { + printf("\b \b"); // Destructive backspace + } + line_index--; + } + forward = false; + break; + + case 13: // Carriage return + // Write buffered line to tty device + tty_write(device_fd, line_buffer, line_index); + tty_write(device_fd, "\r", 1); + optional_local_echo('\r'); + tty_sync(device_fd); + putchar('\r'); + putchar('\n'); + line_index = 0; + forward = false; + break; + + default: + if (line_index < BUFSIZ) + { + line_buffer[line_index++] = input_char; + } + else + { + tio_error_print("Input exceeds maximum line length. Truncating."); + forward = false; + } + } + + // Save 2 latest stdin input characters + previous_char[1] = previous_char[0]; + previous_char[0] = input_char; + + break; + + default: + break; } } }