aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-01-29 13:11:17 +1000
committerDavid Walter Seikel2014-01-29 13:11:17 +1000
commit1162e52e1f7224b18285884c4c5dfe48b4229dd3 (patch)
treedfe31803ec7f42d41e3ae01d3700f854dfdc2aa3
parentAdd bogus MC key, coz tmux is screwing with things. (diff)
downloadboxes-1162e52e1f7224b18285884c4c5dfe48b4229dd3.zip
boxes-1162e52e1f7224b18285884c4c5dfe48b4229dd3.tar.gz
boxes-1162e52e1f7224b18285884c4c5dfe48b4229dd3.tar.bz2
boxes-1162e52e1f7224b18285884c4c5dfe48b4229dd3.tar.xz
Add a CSI parser. We need one for terminal sizing and mouse reports.
-rw-r--r--boxes.c286
1 files changed, 210 insertions, 76 deletions
diff --git a/boxes.c b/boxes.c
index 9deea5f..79b412d 100644
--- a/boxes.c
+++ b/boxes.c
@@ -309,7 +309,6 @@ struct key
309// TODO - Add more shift variations, plus Ctrl & Alt variations when needed. 309// TODO - Add more shift variations, plus Ctrl & Alt variations when needed.
310// TODO - tmux messes with the shift function keys somehow. 310// TODO - tmux messes with the shift function keys somehow.
311// TODO - Add other miscelany that does not use an escape sequence. 311// TODO - Add other miscelany that does not use an escape sequence.
312// TODO - maybe worth writing a proper CSI parse instead. Would be useful for terminal size and mouse reports.
313 312
314// This is sorted by type, though there is some overlap. 313// This is sorted by type, though there is some overlap.
315// Human typing speeds wont need binary searching speeds on this small table. 314// Human typing speeds wont need binary searching speeds on this small table.
@@ -353,64 +352,67 @@ struct key keys[] =
353 {"\x9B", "CSI"}, // CSI The eight bit encoding of "Esc [". 352 {"\x9B", "CSI"}, // CSI The eight bit encoding of "Esc [".
354 353
355 // "Usual" xterm CSI sequences, with ";1" omitted for no modifiers. 354 // "Usual" xterm CSI sequences, with ";1" omitted for no modifiers.
356 {"\x1B[1~", "Home"}, // Duplicate, think I've seen this somewhere. 355 // Even though we have a proper CSI parser, these should still be in this table.
357 {"\x1B[2~", "Ins"}, 356 // Coz we would need a table anyway in the CSI parser, so might as well keep them with the others.
358 {"\x1B[3~", "Del"}, 357 // Also, less code, no need to have a separate scanner for that other table.
359 {"\x1B[4~", "End"}, // Duplicate, think I've seen this somewhere. 358 {"\x9B\x31~", "Home"}, // Duplicate, think I've seen this somewhere.
360 {"\x1B[5~", "PgUp"}, 359 {"\x9B\x32~", "Ins"},
361 {"\x1B[6~", "PgDn"}, 360 {"\x9B\x33~", "Del"},
362 {"\x1B[7~", "Home"}, 361 {"\x9B\x34~", "End"}, // Duplicate, think I've seen this somewhere.
363 {"\x1B[8~", "End"}, 362 {"\x9B\x35~", "PgUp"},
364 {"\x1B[11~", "F1"}, 363 {"\x9B\x36~", "PgDn"},
365 {"\x1B[12~", "F2"}, 364 {"\x9B\x37~", "Home"},
366 {"\x1B[13~", "F3"}, 365 {"\x9B\x38~", "End"},
367 {"\x1B[14~", "F4"}, 366 {"\x9B\x31\x31~", "F1"},
368 {"\x1B[15~", "F5"}, 367 {"\x9B\x31\x32~", "F2"},
369 {"\x1B[17~", "F6"}, 368 {"\x9B\x31\x33~", "F3"},
370 {"\x1B[18~", "F7"}, 369 {"\x9B\x31\x34~", "F4"},
371 {"\x1B[19~", "F8"}, 370 {"\x9B\x31\x35~", "F5"},
372 {"\x1B[20~", "F9"}, 371 {"\x9B\x31\x37~", "F6"},
373 {"\x1B[21~", "F10"}, 372 {"\x9B\x31\x38~", "F7"},
374 {"\x1B[23~", "F11"}, 373 {"\x9B\x31\x39~", "F8"},
375 {"\x1B[24~", "F12"}, 374 {"\x9B\x32\x30~", "F9"},
375 {"\x9B\x32\x31~", "F10"},
376 {"\x9B\x32\x33~", "F11"},
377 {"\x9B\x32\x34~", "F12"},
376 378
377 // As above, ";2" means shift modifier. 379 // As above, ";2" means shift modifier.
378 {"\x1B[1;2~", "Shift Home"}, 380 {"\x9B\x31;2~", "Shift Home"},
379 {"\x1B[2;2~", "Shift Ins"}, 381 {"\x9B\x32;2~", "Shift Ins"},
380 {"\x1B[3;2~", "Shift Del"}, 382 {"\x9B\x33;2~", "Shift Del"},
381 {"\x1B[4;2~", "Shift End"}, 383 {"\x9B\x34;2~", "Shift End"},
382 {"\x1B[5;2~", "Shift PgUp"}, 384 {"\x9B\x35;2~", "Shift PgUp"},
383 {"\x1B[6;2~", "Shift PgDn"}, 385 {"\x9B\x36;2~", "Shift PgDn"},
384 {"\x1B[7;2~", "Shift Home"}, 386 {"\x9B\x37;2~", "Shift Home"},
385 {"\x1B[8;2~", "Shift End"}, 387 {"\x9B\x38;2~", "Shift End"},
386 {"\x1B[11;2~", "Shift F1"}, 388 {"\x9B\x31\x31;2~", "Shift F1"},
387 {"\x1B[12;2~", "Shift F2"}, 389 {"\x9B\x31\x32;2~", "Shift F2"},
388 {"\x1B[13;2~", "Shift F3"}, 390 {"\x9B\x31\x33;2~", "Shift F3"},
389 {"\x1B[14;2~", "Shift F4"}, 391 {"\x9B\x31\x34;2~", "Shift F4"},
390 {"\x1B[15;2~", "Shift F5"}, 392 {"\x9B\x31\x35;2~", "Shift F5"},
391 {"\x1B[17;2~", "Shift F6"}, 393 {"\x9B\x31\x37;2~", "Shift F6"},
392 {"\x1B[18;2~", "Shift F7"}, 394 {"\x9B\x31\x38;2~", "Shift F7"},
393 {"\x1B[19;2~", "Shift F8"}, 395 {"\x9B\x31\x39;2~", "Shift F8"},
394 {"\x1B[20;2~", "Shift F9"}, 396 {"\x9B\x32\x30;2~", "Shift F9"},
395 {"\x1B[21;2~", "Shift F10"}, 397 {"\x9B\x32\x31;2~", "Shift F10"},
396 {"\x1B[23;2~", "Shift F11"}, 398 {"\x9B\x32\x33;2~", "Shift F11"},
397 {"\x1B[24;2~", "Shift F12"}, 399 {"\x9B\x32\x34;2~", "Shift F12"},
398 400
399 // "Normal" Some terminals are special, and it seems they only have four function keys. 401 // "Normal" Some terminals are special, and it seems they only have four function keys.
400 {"\x1B[A", "Up"}, 402 {"\x9B\x41", "Up"},
401 {"\x1B[B", "Down"}, 403 {"\x9B\x42", "Down"},
402 {"\x1B[C", "Right"}, 404 {"\x9B\x43", "Right"},
403 {"\x1B[D", "Left"}, 405 {"\x9B\x44", "Left"},
404 {"\x1B[F", "End"}, 406 {"\x9B\x46", "End"},
405 {"\x1B[H", "Home"}, 407 {"\x9BH", "Home"},
406 {"\x1B[P", "F1"}, 408 {"\x9BP", "F1"},
407 {"\x1B[Q", "F2"}, 409 {"\x9BQ", "F2"},
408 {"\x1B[R", "F3"}, 410 {"\x9BR", "F3"},
409 {"\x1B[S", "F4"}, 411 {"\x9BS", "F4"},
410 {"\x1B[1;2P", "Shift F1"}, 412 {"\x9B\x31;2P", "Shift F1"},
411 {"\x1B[1;2Q", "Shift F2"}, 413 {"\x9B\x31;2Q", "Shift F2"},
412 {"\x1B[1;2R", "Shift F3"}, 414 {"\x9B\x31;2R", "Shift F3"},
413 {"\x1B[1;2S", "Shift F4"}, 415 {"\x9B\x31;2S", "Shift F4"},
414 416
415 // "Application" Esc O is known as SS3 417 // "Application" Esc O is known as SS3
416 {"\x1BOA", "Up"}, 418 {"\x1BOA", "Up"},
@@ -429,13 +431,13 @@ struct key keys[] =
429 {"\x1BOS", "F4"}, 431 {"\x1BOS", "F4"},
430 {"\x1BOT", "F5"}, 432 {"\x1BOT", "F5"},
431 // These two conflict with the above four function key variations. 433 // These two conflict with the above four function key variations.
432 {"\x1B[R", "F6"}, 434 {"\x9BR", "F6"},
433 {"\x1B[S", "F7"}, 435 {"\x9BS", "F7"},
434 {"\x1B[T", "F8"}, 436 {"\x9BT", "F8"},
435 {"\x1B[U", "F9"}, 437 {"\x9BU", "F9"},
436 {"\x1B[V", "F10"}, 438 {"\x9BV", "F10"},
437 {"\x1B[W", "F11"}, 439 {"\x9BW", "F11"},
438 {"\x1B[X", "F12"}, 440 {"\x9BX", "F12"},
439 441
440 // Can't remember, but saw them somewhere. 442 // Can't remember, but saw them somewhere.
441 {"\x1BO1;2P", "Shift F1"}, 443 {"\x1BO1;2P", "Shift F1"},
@@ -493,6 +495,7 @@ typedef struct _view view;
493 495
494typedef void (*boxFunction) (box *box); 496typedef void (*boxFunction) (box *box);
495typedef void (*eventHandler) (view *view); 497typedef void (*eventHandler) (view *view);
498typedef char * (*CSIhandler) (long extra, int *code, int count);
496 499
497struct function 500struct function
498{ 501{
@@ -1819,23 +1822,46 @@ Less and more have the "ZZ" command, but nothing else seems to have multi ordina
1819Some editors have a shortcut command concept. The smallest unique first part of each command will match, as well as anything longer. 1822Some editors have a shortcut command concept. The smallest unique first part of each command will match, as well as anything longer.
1820 A further complication is if we are not implementing some commands that might change what is "shortest unique prefix". 1823 A further complication is if we are not implementing some commands that might change what is "shortest unique prefix".
1821 1824
1822The response from a terminal size check command includes a prefix, a suffix, with the data in the middle.
1823 send "\x1B[s\x1B[999C\x1B[999B\x1B[6n\x1B[u"
1824 Which breaks down to - save cursor position, down 999, right 999, request cursor position (DSR), restore cursor position.
1825 response is "\x1B[ ; R", where the spaces are replaced by digits LINES and COLUMNS respectively. 1825 response is "\x1B[ ; R", where the spaces are replaced by digits LINES and COLUMNS respectively.
1826 And just to screw things up - {"\x1B[1;2R", "Shift F3"}, though no one's going to have a 1 x 2 terminal.
1827
1828 Mouse events are likely similar.
1829*/ 1826*/
1827
1828
1829char *termSize(long extra, int *params, int count)
1830{
1831 int r = params[0], c = params[1];
1832
1833 // TODO - Deal with defaults, though perhaps this wont ever send defaults?
1834 // The heuristic below ignores defaults.
1835 // Check it's not an F3 key variation, coz some of them use the same CSI function code.
1836 // This is a heuristic, we are checking against an unusable terminal size.
1837 // TODO - Double check what the maximum F3 variations can be.
1838 if ((2 == count) && (8 < r) && (8 < c))
1839 {
1840 // TODO - We got a valid terminal size response, do something with it.
1841 }
1842
1843 return NULL;
1844}
1845
1846struct CSI
1847{
1848 char *code;
1849 CSIhandler func;
1850};
1851
1852struct CSI CSI_terminators[] =
1853{
1854 {"R", termSize},
1855 {NULL, NULL}
1856};
1857
1830void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command)) 1858void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command))
1831{ 1859{
1832 struct pollfd pollfds[1]; 1860 struct pollfd pollfds[1];
1833 // Get the initial command set. 1861 // Get the initial command set.
1834 struct keyCommand *ourKeys = lineCommand(extra, ""); 1862 struct keyCommand *ourKeys = lineCommand(extra, "");
1835 char buffer[20]; 1863 char buffer[20], command[20], csFinal[8];
1836 char command[20]; 1864 int csi = 0, csCount = 0, csIndex = 0, csParams[8], index = 0, pollcount = 1;
1837 int pollcount = 1;
1838 int index = 0;
1839// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down. 1865// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down.
1840// uint16_t h = 1; 1866// uint16_t h = 1;
1841// TODO - should check if it's at the top of the box, then grow it down instead of up if so. 1867// TODO - should check if it's at the top of the box, then grow it down instead of up if so.
@@ -1850,6 +1876,14 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1850 int j, p; 1876 int j, p;
1851 char *found = NULL; 1877 char *found = NULL;
1852 1878
1879 if (0 == index)
1880 {
1881 buffer[0] = 0;
1882 csi = 0;
1883 csCount = 0;
1884 csIndex = 0;
1885 }
1886
1853 // Apparently it's more portable to reset this each time. 1887 // Apparently it's more portable to reset this each time.
1854 memset(pollfds, 0, pollcount * sizeof(struct pollfd)); 1888 memset(pollfds, 0, pollcount * sizeof(struct pollfd));
1855 pollfds[0].events = POLLIN; 1889 pollfds[0].events = POLLIN;
@@ -1868,7 +1902,6 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1868 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it. 1902 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it.
1869 strcpy(command, "^["); 1903 strcpy(command, "^[");
1870 index = 0; 1904 index = 0;
1871 buffer[0] = 0;
1872 } 1905 }
1873 // TODO - Send a timer event to lineCommand(). This wont be a precise timed event, but don't think we need one. 1906 // TODO - Send a timer event to lineCommand(). This wont be a precise timed event, but don't think we need one.
1874 } 1907 }
@@ -1905,13 +1938,29 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1905 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]); 1938 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]);
1906 fflush(stderr); 1939 fflush(stderr);
1907 index = 0; 1940 index = 0;
1908 buffer[0] = 0;
1909 } 1941 }
1910 else buffer[index] = 0; 1942 else buffer[index] = 0;
1911 } 1943 }
1912 } 1944 }
1913 } 1945 }
1914 1946
1947 // Check if it's a CSI before we check for the known key sequences.
1948 if ('\x9B' == buffer[0])
1949 csi = 1;
1950 if (('\x1B' == buffer[0]) && ('[' == buffer[1]))
1951 csi = 2;
1952 if (('\xC2' == buffer[0]) && ('\x9B' == buffer[1]))
1953 csi = 2;
1954 if (2 == csi)
1955 {
1956 buffer[0] = '\x9B';
1957 for (j = 1; buffer[j]; j++)
1958 buffer[j] = buffer[j + 1];
1959 index--;
1960 csi = 1;
1961 }
1962
1963 // Check for known key sequences.
1915 // For a real timeout checked Esc, buffer is now empty, so this for loop wont find it anyway. 1964 // For a real timeout checked Esc, buffer is now empty, so this for loop wont find it anyway.
1916 // While it's true we could avoid it by checking, the user already had to wait for a time out, and this loop wont take THAT long. 1965 // While it's true we could avoid it by checking, the user already had to wait for a time out, and this loop wont take THAT long.
1917 for (j = 0; keys[j].code; j++) // Search for multibyte keys and control keys. 1966 for (j = 0; keys[j].code; j++) // Search for multibyte keys and control keys.
@@ -1920,11 +1969,94 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1920 { 1969 {
1921 strcat(command, keys[j].name); 1970 strcat(command, keys[j].name);
1922 index = 0; 1971 index = 0;
1923 buffer[0] = 0; 1972 csi = 0;
1924 break; 1973 break;
1925 } 1974 }
1926 } 1975 }
1927 1976
1977 // Find out if it's a CSI sequence that's not in the known key sequences.
1978 if (csi)
1979 {
1980 /* ECMA-048 section 5.2 defines this, and is unreadable.
1981 General CSI format - CSI [private] n1 ; n2 [extra] final
1982 private 0x3c to 0x3f [<=>?] if first byte is one of these, this is a private command, if it's one of the other n1 ones, it's not private.
1983 n1 0x30 to 0x3f [01234567890:;<=>?] ASCII digits forming a "number"
1984 0x3a [:] used for floats, not expecting any. Could also be used as some other sort of inter digit separator.
1985 0x3b [;] separates the parameters
1986 extra 0x20 to 0x2f [ !"#$%&'()*+,-./] Can be multiple, likely isn't.
1987 final 0x40 to 0x7e "@A .. Z[\]^_`a .. z{|}~" it's private if 0x70 to 0x7e [p ..z{|}~]
1988 Though the "private" ~ is used for key codes.
1989 We also have SS3 "\x1BO" for other keys, but that's not a CSI.
1990 C0 controls, DEL (0x7f), or high characters are undefined.
1991TODO So abort the current CSI and start from scratch.
1992 */
1993
1994 char *t;
1995
1996 csIndex = 1;
1997 csFinal[0] = 0;
1998 // Unspecified params default to a value that is command dependant.
1999 // However, they will never be negative, so we can use -1 to flag a default value.
2000 for (j = 0; j < sizeof(csParams); j++)
2001 csParams[j] = -1;
2002
2003 if ('M' == buffer[1])
2004 {
2005 // TODO - We have a mouse report, which is CSI M ..., where the rest is binary encoded, more or less. Not fitting into the CSI format.
2006 }
2007 else
2008 {
2009 // TODO - Using rindex here, coz index is a variable in this scope. Should rename index.
2010 // Check for the private bit.
2011 if (rindex("<=>?", buffer[1]))
2012 {
2013 csFinal[0] = buffer[1];
2014 csFinal[1] = 0;
2015 csIndex++;
2016 }
2017
2018 // Decode parameters.
2019 j = csIndex;
2020 do
2021 {
2022 // So we know when we get to the end of parameter space.
2023 t = rindex("01234567890:;<=>?", buffer[j + 1]);
2024 // See if we passed a paremeter.
2025 if ((';' == buffer[j]) || (NULL == t))
2026 {
2027 buffer[j] = 0;
2028 // Empty parameters are default parameters, so only deal with non defaults.
2029 if (';' != buffer[csIndex] || (NULL == t))
2030 {
2031 // TODO - Might be ":" in the number somewhere, but we are not expecting any in anything we do.
2032 csParams[csCount] = atoi(&buffer[csIndex]);
2033 }
2034 csCount++;
2035 csIndex = j + 1;
2036 }
2037 j++;
2038 }
2039 while (t);
2040
2041 // Get the final command sequence, and search for it.
2042 strcat(csFinal, &buffer[csIndex]);
2043 for (j = 0; CSI_terminators[j].code; j++)
2044 {
2045 if (strcmp(CSI_terminators[j].code, csFinal) == 0)
2046 {
2047 t = CSI_terminators[j].func(extra, csParams, csCount);
2048 if (t)
2049 strcpy(command, t);
2050 break;
2051 }
2052 }
2053 }
2054
2055 csi = 0;
2056 // Wether or not it's a CSI we understand, it's been handled either here or in the key sequence scanning above.
2057 index = 0;
2058 }
2059
1928 // See if it's an ordinary key, 2060 // See if it's an ordinary key,
1929 if ((1 == index) && isprint(buffer[0])) 2061 if ((1 == index) && isprint(buffer[0]))
1930 { 2062 {
@@ -1945,7 +2077,6 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1945 else lineChar(extra, buffer); 2077 else lineChar(extra, buffer);
1946 } 2078 }
1947 index = 0; 2079 index = 0;
1948 buffer[0] = 0;
1949 } 2080 }
1950 2081
1951 if (command[0]) // Search for a bound key. 2082 if (command[0]) // Search for a bound key.
@@ -2685,6 +2816,9 @@ void boxes_main(void)
2685 tcsetattr(0, TCSANOW, &termio); 2816 tcsetattr(0, TCSANOW, &termio);
2686 2817
2687 // TODO - set up a handler for SIGWINCH to find out when the terminal has been resized. 2818 // TODO - set up a handler for SIGWINCH to find out when the terminal has been resized.
2819 // TODO - send "\x1B[s\x1B[999C\x1B[999B\x1B[6n\x1B[u"
2820 // Which breaks down to - save cursor position, down 999, right 999, request cursor position (DSR), restore cursor position.
2821 // Already got the stub for dealing with the response.
2688 terminal_size(&W, &H); 2822 terminal_size(&W, &H);
2689 if (toys.optflags & FLAG_w) 2823 if (toys.optflags & FLAG_w)
2690 W = TT.w; 2824 W = TT.w;