Refactor terminal input to remove ldiscucs.c.

The functions that previously lived in it now live in terminal.c
itself; they've been renamed term_keyinput and term_keyinputw, and
their function is to add data to the terminal's user input buffer from
a char or wchar_t string respectively.

They sit more comfortably in terminal.c anyway, because their whole
point is to translate into the character encoding that the terminal is
currently configured to use. Also, making them part of the terminal
code means they can also take care of calling term_seen_key_event(),
which simplifies most of the call sites in the GTK and Windows front
ends.

Generation of text _inside_ terminal.c, from responses to query escape
sequences, is therefore not done by calling those external entry
points: we send those responses directly to the ldisc, so that they
don't count as keypresses for all the user-facing purposes like bell
overload handling and scrollback reset. To make _that_ convenient,
I've arranged that most of the code that previously lived in
lpage_send and luni_send is now in separate translation functions, so
those can still be called from situations where you're not going to do
the default thing with the translated data.

(However, pasted data _does_ still count as close enough to a keypress
to call term_seen_key_event - but it clears the 'interactive' flag
when the data is passed on to the line discipline, which tweaks a
minor detail of control-char handling in line ending mode but mostly
just means pastes aren't interrupted.)
This commit is contained in:
Simon Tatham 2019-06-17 20:13:55 +01:00
Родитель c800834d63
Коммит 71e42b04a5
6 изменённых файлов: 149 добавлений и 149 удалений

2
Recipe
Просмотреть файл

@ -239,7 +239,7 @@ CFLAGS += -DWINVER=0x0500 -D_WIN32_WINDOWS=0x0410 -D_WIN32_WINNT=0x0500
CONF = conf marshal
# Terminal emulator and its (platform-independent) dependencies.
TERMINAL = terminal stripctrl wcwidth ldiscucs logging tree234 minibidi
TERMINAL = terminal stripctrl wcwidth logging tree234 minibidi
+ config dialog CONF
# GUI front end and terminal emulator (putty, puttytel).

Просмотреть файл

@ -1,83 +0,0 @@
/*
* ldisc.c: PuTTY line discipline. Sits between the input coming
* from keypresses in the window, and the output channel leading to
* the back end. Implements echo and/or local line editing,
* depending on what's currently configured.
*/
#include <stdio.h>
#include <ctype.h>
#include "putty.h"
#include "terminal.h"
#include "ldisc.h"
void lpage_send(Ldisc *ldisc,
int codepage, const char *buf, int len, bool interactive)
{
wchar_t *widebuffer = 0;
int widesize = 0;
int wclen;
if (codepage < 0) {
ldisc_send(ldisc, buf, len, interactive);
return;
}
widesize = len * 2;
widebuffer = snewn(widesize, wchar_t);
wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize);
luni_send(ldisc, widebuffer, wclen, interactive);
sfree(widebuffer);
}
void luni_send(Ldisc *ldisc, const wchar_t *widebuf, int len, bool interactive)
{
int ratio = (in_utf(ldisc->term))?3:1;
char *linebuffer;
int linesize;
int i;
char *p;
linesize = len * ratio * 2;
linebuffer = snewn(linesize, char);
if (in_utf(ldisc->term)) {
/* UTF is a simple algorithm */
for (p = linebuffer, i = 0; i < len; i++) {
unsigned long ch = widebuf[i];
if (IS_SURROGATE(ch)) {
#ifdef PLATFORM_IS_UTF16
if (i+1 < len) {
unsigned long ch2 = widebuf[i+1];
if (IS_SURROGATE_PAIR(ch, ch2)) {
ch = FROM_SURROGATES(ch, ch2);
i++;
}
} else
#endif
{
/* Unrecognised UTF-16 sequence */
ch = '.';
}
}
p += encode_utf8(p, ch);
}
} else {
int rv;
rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 0, widebuf, len,
linebuffer, linesize, NULL, ldisc->term->ucsdata);
if (rv >= 0)
p = linebuffer + rv;
else
p = linebuffer;
}
if (p > linebuffer)
ldisc_send(ldisc, linebuffer, p - linebuffer, interactive);
sfree(linebuffer);
}

Просмотреть файл

@ -1643,6 +1643,8 @@ void term_set_focus(Terminal *term, bool has_focus);
char *term_get_ttymode(Terminal *term, const char *mode);
int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
void term_set_trust_status(Terminal *term, bool trusted);
void term_keyinput(Terminal *, int codepage, const void *buf, int len);
void term_keyinputw(Terminal *, const wchar_t * widebuf, int len);
typedef enum SmallKeypadKey {
SKK_HOME, SKK_END, SKK_INSERT, SKK_DELETE, SKK_PGUP, SKK_PGDN,
@ -1779,13 +1781,6 @@ void ldisc_free(Ldisc *);
void ldisc_send(Ldisc *, const void *buf, int len, bool interactive);
void ldisc_echoedit_update(Ldisc *);
/*
* Exports from ldiscucs.c.
*/
void lpage_send(Ldisc *, int codepage, const char *buf, int len,
bool interactive);
void luni_send(Ldisc *, const wchar_t * widebuf, int len, bool interactive);
/*
* Exports from sshrand.c.
*/

Просмотреть файл

@ -114,6 +114,7 @@ static void deselect(Terminal *);
static void term_print_finish(Terminal *);
static void scroll(Terminal *, int, int, int, bool);
static void parse_optionalrgb(optionalrgb *out, unsigned *values);
static void term_added_data(Terminal *term);
static termline *newtermline(Terminal *term, int cols, bool bce)
{
@ -2955,6 +2956,84 @@ static void term_display_graphic_char(Terminal *term, unsigned long c)
seen_disp_event(term);
}
static strbuf *term_input_data_from_unicode(
Terminal *term, const wchar_t *widebuf, int len)
{
strbuf *buf = strbuf_new();
if (in_utf(term)) {
/*
* Translate input wide characters into UTF-8 to go in the
* terminal's input data queue.
*/
for (int i = 0; i < len; i++) {
unsigned long ch = widebuf[i];
if (IS_SURROGATE(ch)) {
#ifdef PLATFORM_IS_UTF16
if (i+1 < len) {
unsigned long ch2 = widebuf[i+1];
if (IS_SURROGATE_PAIR(ch, ch2)) {
ch = FROM_SURROGATES(ch, ch2);
i++;
}
} else
#endif
{
/* Unrecognised UTF-16 sequence */
ch = '.';
}
}
char utf8_chr[6];
put_data(buf, utf8_chr, encode_utf8(utf8_chr, ch));
}
} else {
/*
* Call to the character-set subsystem to translate into
* whatever charset the terminal is currently configured in.
*
* Since the terminal doesn't currently support any multibyte
* character set other than UTF-8, we can assume here that
* there will be at most one output byte per input wchar_t.
*/
char *bufptr = strbuf_append(buf, len);
int rv;
rv = wc_to_mb(term->ucsdata->line_codepage, 0, widebuf, len,
bufptr, len, NULL, term->ucsdata);
buf->len = rv < 0 ? 0 : rv;
}
return buf;
}
static strbuf *term_input_data_from_charset(
Terminal *term, int codepage, const char *str, int len)
{
strbuf *buf;
if (codepage < 0) {
buf = strbuf_new();
put_data(buf, str, len);
} else {
int widesize = len * 2; /* allow for UTF-16 surrogates */
wchar_t *widebuf = snewn(widesize, wchar_t);
int widelen = mb_to_wc(codepage, 0, str, len, widebuf, widesize);
buf = term_input_data_from_unicode(term, widebuf, widelen);
sfree(widebuf);
}
return buf;
}
static inline void term_keyinput_internal(
Terminal *term, const void *buf, int len, bool interactive)
{
if (term->ldisc)
ldisc_send(term->ldisc, buf, len, interactive);
term_seen_key_event(term);
}
unsigned long term_translate(
Terminal *term, struct term_utf8_decode *utf8, unsigned char c)
{
@ -3227,8 +3306,11 @@ static void term_out(Terminal *term)
*/
compatibility(ANSIMIN);
if (term->ldisc) {
lpage_send(term->ldisc, DEFAULT_CODEPAGE,
term->answerback, term->answerbacklen, false);
strbuf *buf = term_input_data_from_charset(
term, DEFAULT_CODEPAGE,
term->answerback, term->answerbacklen);
ldisc_send(term->ldisc, buf->s, buf->len, false);
strbuf_free(buf);
}
break;
case '\007': /* BEL: Bell */
@ -6231,9 +6313,12 @@ static void term_paste_callback(void *vterm)
if (term->paste_buffer[term->paste_pos + n++] == '\015')
break;
}
if (term->ldisc)
luni_send(term->ldisc, term->paste_buffer + term->paste_pos, n,
false);
if (term->ldisc) {
strbuf *buf = term_input_data_from_unicode(
term, term->paste_buffer + term->paste_pos, n);
term_keyinput_internal(term, buf->s, buf->len, false);
strbuf_free(buf);
}
term->paste_pos += n;
if (term->paste_pos < term->paste_len) {
@ -6336,8 +6421,12 @@ void term_do_paste(Terminal *term, const wchar_t *data, int len)
/* Assume a small paste will be OK in one go. */
if (term->paste_len < 256) {
if (term->ldisc)
luni_send(term->ldisc, term->paste_buffer, term->paste_len, false);
if (term->ldisc) {
strbuf *buf = term_input_data_from_unicode(
term, term->paste_buffer, term->paste_len);
term_keyinput_internal(term, buf->s, buf->len, false);
strbuf_free(buf);
}
if (term->paste_buffer)
sfree(term->paste_buffer);
term->paste_buffer = 0;
@ -6840,6 +6929,33 @@ int format_numeric_keypad_key(char *buf, Terminal *term, char key,
return p - buf;
}
void term_keyinputw(Terminal *term, const wchar_t *widebuf, int len)
{
strbuf *buf = term_input_data_from_unicode(term, widebuf, len);
if (buf->len)
term_keyinput_internal(term, buf->s, buf->len, true);
strbuf_free(buf);
}
void term_keyinput(Terminal *term, int codepage, const void *str, int len)
{
if (codepage < 0 || codepage == term->ucsdata->line_codepage) {
/*
* This text needs no translation, either because it's already
* in the right character set, or because we got the special
* codepage value -1 from our caller which means 'this data
* should be charset-agnostic, just send it raw' (for really
* simple things like control characters).
*/
term_keyinput_internal(term, str, len, true);
} else {
strbuf *buf = term_input_data_from_charset(term, codepage, str, len);
if (buf->len)
term_keyinput_internal(term, buf->s, buf->len, true);
strbuf_free(buf);
}
}
void term_nopaste(Terminal *term)
{
if (term->paste_len == 0)

Просмотреть файл

@ -1932,8 +1932,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
*/
output[end] = '\0'; /* NUL-terminate */
generated_something = true;
if (inst->ldisc)
ldisc_send(inst->ldisc, output+start, -2, true);
term_keyinput(inst->term, -1, output+start, -2);
} else if (!inst->direct_to_font) {
if (!use_ucsoutput) {
#ifdef KEY_EVENT_DIAGNOSTICS
@ -1952,9 +1951,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
sfree(string_string);
#endif
generated_something = true;
if (inst->ldisc)
lpage_send(inst->ldisc, output_charset, output+start,
end-start, true);
term_keyinput(inst->term, output_charset,
output+start, end-start);
} else {
#ifdef KEY_EVENT_DIAGNOSTICS
char *string_string = dupstr("");
@ -1977,8 +1975,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
* keysym, so use that instead.
*/
generated_something = true;
if (inst->ldisc)
luni_send(inst->ldisc, ucsoutput+start, end-start, true);
term_keyinputw(inst->term, ucsoutput+start, end-start);
}
} else {
/*
@ -2001,12 +1998,10 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
sfree(string_string);
#endif
generated_something = true;
if (inst->ldisc)
ldisc_send(inst->ldisc, output+start, end-start, true);
term_keyinput(inst->term, -1, output+start, end-start);
}
show_mouseptr(inst, false);
term_seen_key_event(inst->term);
}
if (generated_something)
@ -2034,10 +2029,8 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data)
sfree(string_string);
#endif
if (inst->ldisc)
lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), true);
term_keyinput(inst->term, CS_UTF8, str, strlen(str));
show_mouseptr(inst, false);
term_seen_key_event(inst->term);
key_pressed(inst);
}
#endif

Просмотреть файл

@ -3245,9 +3245,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
* messages. We _have_ to buffer everything
* we're sent.
*/
term_seen_key_event(term);
if (ldisc)
ldisc_send(ldisc, buf, len, true);
term_keyinput(term, -1, buf, len);
show_mouseptr(false);
}
}
@ -3289,10 +3287,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
/*
* Jaeyoun Chung reports that Korean character
* input doesn't work correctly if we do a single
* luni_send() covering the whole of buff. So
* instead we luni_send the characters one by one.
* term_keyinputw covering the whole of buff. So
* instead we send the characters one by one.
*/
term_seen_key_event(term);
/* don't divide SURROGATE PAIR */
if (ldisc) {
for (i = 0; i < n; i += 2) {
@ -3300,13 +3297,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (IS_HIGH_SURROGATE(hs) && i+2 < n) {
WCHAR ls = *(unsigned short *)(buff+i+2);
if (IS_LOW_SURROGATE(ls)) {
luni_send(ldisc, (unsigned short *)(buff+i),
2, true);
term_keyinputw(
term, (unsigned short *)(buff+i), 2);
i += 2;
continue;
}
}
luni_send(ldisc, (unsigned short *)(buff+i), 1, true);
term_keyinputw(
term, (unsigned short *)(buff+i), 1);
}
}
free(buff);
@ -3321,14 +3319,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
buf[1] = wParam;
buf[0] = wParam >> 8;
term_seen_key_event(term);
if (ldisc)
lpage_send(ldisc, kbd_codepage, buf, 2, true);
term_keyinput(term, kbd_codepage, buf, 2);
} else {
char c = (unsigned char) wParam;
term_seen_key_event(term);
if (ldisc)
lpage_send(ldisc, kbd_codepage, &c, 1, true);
term_keyinput(term, kbd_codepage, &c, 1);
}
return (0);
case WM_CHAR:
@ -3349,11 +3344,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
wchar_t pair[2];
pair[0] = pending_surrogate;
pair[1] = c;
term_seen_key_event(term);
luni_send(ldisc, pair, 2, true);
term_keyinputw(term, pair, 2);
} else if (!IS_SURROGATE(c)) {
term_seen_key_event(term);
luni_send(ldisc, &c, 1, true);
term_keyinputw(term, &c, 1);
}
}
return 0;
@ -4691,9 +4684,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
return 0;
}
keybuf = nc;
term_seen_key_event(term);
if (ldisc)
luni_send(ldisc, &keybuf, 1, true);
term_keyinputw(term, &keybuf, 1);
continue;
}
@ -4703,9 +4694,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
if (alt_sum) {
if (in_utf(term) || ucsdata.dbcs_screenfont) {
keybuf = alt_sum;
term_seen_key_event(term);
if (ldisc)
luni_send(ldisc, &keybuf, 1, true);
term_keyinputw(term, &keybuf, 1);
} else {
char ch = (char) alt_sum;
/*
@ -4717,33 +4706,23 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
* messages. We _have_ to buffer
* everything we're sent.
*/
term_seen_key_event(term);
if (ldisc)
ldisc_send(ldisc, &ch, 1, true);
term_keyinput(term, -1, &ch, 1);
}
alt_sum = 0;
} else {
term_seen_key_event(term);
if (ldisc)
luni_send(ldisc, &wch, 1, true);
term_keyinputw(term, &wch, 1);
}
} else {
if(capsOn && wch < 0x80) {
WCHAR cbuf[2];
cbuf[0] = 27;
cbuf[1] = xlat_uskbd2cyrllic(wch);
term_seen_key_event(term);
if (ldisc)
luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt,
true);
term_keyinputw(term, cbuf+!left_alt, 1+!!left_alt);
} else {
WCHAR cbuf[2];
cbuf[0] = '\033';
cbuf[1] = wch;
term_seen_key_event(term);
if (ldisc)
luni_send(ldisc, cbuf +!left_alt, 1+!!left_alt,
true);
term_keyinputw(term, cbuf +!left_alt, 1+!!left_alt);
}
}
show_mouseptr(false);