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:
130
terminal.c
130
terminal.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)
|
||||
|
Reference in New Issue
Block a user