1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-18 19:41:01 -05:00

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
parent c800834d63
commit 71e42b04a5
6 changed files with 149 additions and 149 deletions

View File

@ -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)