Skip to content

Commit 6468333

Browse files
committed
Improve key handling to support multiple consecutive sequences
Signed-off-by: Jakub Horký <jakub.github@horky.net>
1 parent eda9b61 commit 6468333

File tree

1 file changed

+101
-87
lines changed

1 file changed

+101
-87
lines changed

lib/tty/key.c

Lines changed: 101 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ const key_code_name_t key_name_conv_tab[] = {
222222

223223
#define MC_USEC_PER_MSEC 1000
224224

225-
/* The maximum sequence length (32 + null terminator) */
226-
#define SEQ_BUFFER_LEN 33
225+
/* The buffer can handle multiple sequences */
226+
#define SEQ_BUFFER_LEN 100
227227

228228
/*** file scope type declarations ****************************************************************/
229229

@@ -555,6 +555,7 @@ static GSList *select_list = NULL;
555555
static int seq_buffer[SEQ_BUFFER_LEN];
556556
static int *seq_append = NULL;
557557

558+
static int seq_buffer_temp[SEQ_BUFFER_LEN];
558559
static char seq_char_buffer[SEQ_BUFFER_LEN];
559560

560561
static int *pending_keys = NULL;
@@ -1727,6 +1728,7 @@ get_key_code (int no_delay)
17271728
int c;
17281729
int i;
17291730
int modifiers;
1731+
int *seq_complex;
17301732
csi_command_t csi;
17311733
gchar utf8char[7];
17321734
static key_def *this = NULL, *parent;
@@ -1742,112 +1744,129 @@ get_key_code (int no_delay)
17421744
pend_send:
17431745
if (pending_keys != NULL)
17441746
{
1745-
gboolean bad_or_complex_seq;
1747+
gboolean bad_seq;
17461748

1747-
c = *pending_keys++;
1748-
while (c == ESC_CHAR)
1749-
c = ALT (*pending_keys++);
1750-
1751-
bad_or_complex_seq = (*pending_keys != ESC_CHAR && *pending_keys != '\0');
1752-
1753-
if (bad_or_complex_seq)
1749+
// May be a complex sequence
1750+
complex_seq:
1751+
while (pending_keys != NULL && pending_keys[0] == ESC_CHAR && pending_keys[1] == '[')
17541752
{
17551753
tty_nodelay (TRUE);
17561754
while ((c = tty_lowlevel_getch ()) >= 0)
17571755
push_char (c);
17581756
tty_nodelay (FALSE);
17591757

1760-
// Check for complex sequences if all chars are 8bit only
1761-
i = 0;
1762-
while (seq_buffer[i] != '\0')
1763-
{
1764-
if (seq_buffer[i] > 255)
1765-
goto no_complex_seq;
1766-
seq_char_buffer[i] = seq_buffer[i];
1758+
seq_complex = pending_keys;
1759+
pending_keys = seq_append = NULL;
17671760

1768-
i++;
1761+
// Check for complex sequence until any KEY_* constant (above 8bit)
1762+
for (i = 0; seq_complex[i] != '\0'; i++)
1763+
{
1764+
if (seq_complex[i] > 0xFF)
1765+
{
1766+
pending_keys = seq_append = &seq_complex[i];
1767+
break;
1768+
}
1769+
seq_char_buffer[i] = seq_complex[i];
17691770
}
17701771
seq_char_buffer[i] = '\0';
17711772

1772-
if (seq_char_buffer[0] == ESC_CHAR && seq_char_buffer[1] == '[')
1773-
{
1774-
const char *seq_char_buffer_ptr = &seq_char_buffer[2];
1775-
if (!parse_csi (&csi, &seq_char_buffer_ptr, &seq_char_buffer[i]))
1776-
goto no_complex_seq;
1773+
const char *seq_char_buffer_ptr = &seq_char_buffer[2];
1774+
if (!parse_csi (&csi, &seq_char_buffer_ptr, &seq_char_buffer[i]))
1775+
continue;
17771776

1778-
// Check for Kitty Keyboard Protocol including backward compatibility sequences
1777+
char final_byte = *(seq_char_buffer_ptr - 1);
1778+
if (*seq_char_buffer_ptr != '\0')
1779+
pending_keys = seq_append = &seq_buffer[seq_char_buffer_ptr - seq_char_buffer];
17791780

1780-
if ((seq_char_buffer[i - 1] == 'u' && csi.param_count >= 1)
1781-
|| (seq_char_buffer[i - 1] == '~' && csi.param_count >= 1)
1782-
|| (seq_char_buffer[i - 1] >= 'A' && seq_char_buffer[i - 1] <= 'F')
1783-
|| (seq_char_buffer[i - 1] == 'H')
1784-
|| (seq_char_buffer[i - 1] >= 'P' && seq_char_buffer[i - 1] <= 'S'))
1785-
{
1786-
if (csi.private_mode != 0)
1787-
goto no_complex_seq;
1781+
// Check for Kitty Keyboard Protocol including backward compatibility sequences:
1782+
// CSI parameters [u~ABCDEFHPQS]
1783+
if ((final_byte == 'u' && csi.param_count >= 1)
1784+
|| (final_byte == '~' && csi.param_count >= 1)
1785+
|| (final_byte >= 'A' && final_byte <= 'F') || (final_byte == 'H')
1786+
|| (final_byte >= 'P' && final_byte <= 'S'))
1787+
{
1788+
if (csi.private_mode != 0)
1789+
continue;
17881790

1789-
if (csi.param_count >= 2)
1790-
modifiers = ((csi.params[1][0] - 1) << 12) & KEY_M_MASK;
1791-
else
1792-
modifiers = 0;
1791+
if (csi.param_count >= 2)
1792+
modifiers = ((csi.params[1][0] - 1) << 12) & KEY_M_MASK;
1793+
else
1794+
modifiers = 0;
17931795

1794-
if (csi.param_count == 0)
1795-
csi.params[0][0] = 1;
1796+
if (csi.param_count == 0)
1797+
csi.params[0][0] = 1;
17961798

1797-
int j = 0;
1798-
while (kitty_key_defines[j].code)
1799+
for (int j = 0; kitty_key_defines[j].code != 0; j++)
1800+
{
1801+
if (kitty_key_defines[j].kitty_code == csi.params[0][0]
1802+
&& kitty_key_defines[j].final_byte == final_byte)
17991803
{
1800-
if (kitty_key_defines[j].kitty_code == csi.params[0][0]
1801-
&& kitty_key_defines[j].final_byte == seq_char_buffer[i - 1])
1802-
{
1803-
c = kitty_key_defines[j].code;
1804-
if (c == -1)
1805-
goto no_complex_seq;
1806-
c |= modifiers;
1807-
1808-
pending_keys = seq_append = NULL;
1809-
goto done;
1810-
}
1811-
1812-
j++;
1813-
}
1804+
c = kitty_key_defines[j].code;
1805+
if (c == -1)
1806+
goto complex_seq; // outer continue
1807+
c |= modifiers;
18141808

1815-
// Translate shifted chars so command line input works
1816-
if (csi.params[0][1])
1817-
{
1818-
c = csi.params[0][1];
1819-
if (modifiers & KEY_M_SHIFT)
1820-
modifiers &= ~KEY_M_SHIFT;
1821-
}
1822-
else
1823-
{
1824-
c = csi.params[0][0];
1825-
if ((csi.params[0][2] || (c >= '0' && c <= '9')) && modifiers & KEY_M_SHIFT)
1826-
modifiers &= ~KEY_M_SHIFT;
1809+
goto done;
18271810
}
1811+
}
18281812

1829-
if (c >= 0x80)
1830-
{
1831-
// Unicode char
1832-
i = g_unichar_to_utf8 (c, (gchar *) &utf8char);
1813+
// Translate shifted chars so command line input works
1814+
if (csi.params[0][1])
1815+
{
1816+
c = csi.params[0][1];
1817+
if (modifiers & KEY_M_SHIFT)
1818+
modifiers &= ~KEY_M_SHIFT;
1819+
}
1820+
else
1821+
{
1822+
c = csi.params[0][0];
1823+
if ((csi.params[0][2] || (c >= '0' && c <= '9')) && modifiers & KEY_M_SHIFT)
1824+
modifiers &= ~KEY_M_SHIFT;
1825+
}
18331826

1834-
c = utf8char[0] & 0xFF;
1835-
pending_keys = seq_append = seq_buffer;
1836-
for (j = 1; j < i; j++)
1837-
push_char (utf8char[j] & 0xFF);
1838-
goto done;
1839-
}
1827+
if (c >= 0x80)
1828+
{
1829+
// Unicode char
1830+
i = g_unichar_to_utf8 (c, (gchar *) &utf8char);
18401831

1841-
if ((modifiers & KEY_M_CTRL) && (c == ' ' || (c >= 0x40 && c <= 0x7e)))
1842-
c = XCTRL (c);
1832+
seq_buffer_temp[0] = '\0';
1833+
if (pending_keys != NULL)
1834+
for (int j = 0; *pending_keys != '\0' && j < SEQ_BUFFER_LEN; j++)
1835+
seq_buffer_temp[j] = pending_keys[j];
18431836

1844-
c |= modifiers;
1837+
c = utf8char[0] & 0xFF;
1838+
pending_keys = seq_append = seq_buffer;
1839+
for (int j = 1; j < i; j++)
1840+
push_char (utf8char[j] & 0xFF);
1841+
1842+
for (i = 0; seq_buffer_temp[i] != '\0' && i < SEQ_BUFFER_LEN; i++)
1843+
push_char (seq_buffer_temp[i]);
1844+
1845+
goto done;
18451846
}
18461847

1847-
pending_keys = seq_append = NULL;
1848-
goto done;
1848+
if ((modifiers & KEY_M_CTRL) && (c == ' ' || (c >= 0x40 && c <= 0x7e)))
1849+
c = XCTRL (c);
1850+
1851+
c |= modifiers;
18491852
}
18501853

1854+
goto done;
1855+
}
1856+
1857+
if (pending_keys == NULL)
1858+
return -1;
1859+
1860+
c = *pending_keys++;
1861+
while (c == ESC_CHAR)
1862+
c = ALT (*pending_keys++);
1863+
1864+
bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != '\0');
1865+
if (*pending_keys == '\0' || bad_seq)
1866+
pending_keys = seq_append = NULL;
1867+
1868+
if (bad_seq)
1869+
{
18511870
/* This is an unknown ESC sequence.
18521871
* To prevent interpreting its tail as a random garbage,
18531872
* eat and discard all buffered and quickly following chars.
@@ -1859,12 +1878,7 @@ get_key_code (int no_delay)
18591878
while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
18601879
;
18611880
}
1862-
1863-
no_complex_seq:
1864-
if (*pending_keys == '\0' || bad_or_complex_seq)
1865-
pending_keys = seq_append = NULL;
1866-
1867-
if (!bad_or_complex_seq)
1881+
else
18681882
goto done;
18691883
}
18701884

0 commit comments

Comments
 (0)