aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/boxes.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--boxes.c266
1 files changed, 114 insertions, 152 deletions
diff --git a/boxes.c b/boxes.c
index 0004c2f..a526113 100644
--- a/boxes.c
+++ b/boxes.c
@@ -303,6 +303,7 @@ struct key
303// Conversely, some terminals send "Esc somekey" when you do "Alt somekey". 303// Conversely, some terminals send "Esc somekey" when you do "Alt somekey".
304// Those MC Esc variants might be used on Macs for other things? 304// Those MC Esc variants might be used on Macs for other things?
305// TODO - Don't think I got all the linux console variations. 305// TODO - Don't think I got all the linux console variations.
306// TODO - tmux messes with the shift function keys somehow.
306// TODO - Add more shift variations, plus Ctrl & Alt variations. 307// TODO - Add more shift variations, plus Ctrl & Alt variations.
307// TODO - Add other miscelany that does not use an escape sequence. Including mouse events. 308// TODO - Add other miscelany that does not use an escape sequence. Including mouse events.
308// TODO - Perhaps sort this for quicker searching, OR to say which terminal is which, though there is some overlap. 309// TODO - Perhaps sort this for quicker searching, OR to say which terminal is which, though there is some overlap.
@@ -380,40 +381,38 @@ struct key keys[] =
380 {"\x1B[23;2~", "Shift F11"}, 381 {"\x1B[23;2~", "Shift F11"},
381 {"\x1B[24;2~", "Shift F12"}, 382 {"\x1B[24;2~", "Shift F12"},
382 383
383 // These are here for documentation, but some are mapped to particular key names. 384// {"\x00", "^@"}, // NUL Commented out coz it's the C string terminator, and may confuse things.
384 // The commented out control keys are handled in editLine(), or just used via "^X". 385 {"\x01", "^A"}, // SOH
385// {"\x00", "^@"}, // NUL 386 {"\x02", "^B"}, // STX
386// {"\x01", "^A"}, // SOH 387 {"\x03", "^C"}, // ETX SIGTERM
387// {"\x02", "^B"}, // STX 388 {"\x04", "^D"}, // EOT
388// {"\x03", "^C"}, // ETX 389 {"\x05", "^E"}, // ENQ
389// {"\x04", "^D"}, // EOT 390 {"\x06", "^F"}, // ACK
390// {"\x05", "^E"}, // ENQ 391 {"\x07", "^G"}, // BEL
391// {"\x06", "^F"}, // ACK
392// {"\x07", "^G"}, // BEL
393 {"\x08", "Del"}, // BS Delete key, usually. 392 {"\x08", "Del"}, // BS Delete key, usually.
394 {"\x09", "Tab"}, // HT Tab key. 393 {"\x09", "Tab"}, // HT Tab key.
395 {"\x0A", "Return"}, // LF Return key. Roxterm at least is translating both Ctrl-J and Ctrl-M into this. 394 {"\x0A", "Return"}, // LF Return key. Roxterm at least is translating both Ctrl-J and Ctrl-M into this.
396// {"\x0B", "^K"}, // VT 395 {"\x0B", "^K"}, // VT
397// {"\x0C", "^L"}, // FF 396 {"\x0C", "^L"}, // FF
398// {"\x0D", "^M"}, // CR 397 {"\x0D", "^M"}, // CR Other Return key, usually.
399// {"\x0E", "^N"}, // SO 398 {"\x0E", "^N"}, // SO
400// {"\x0F", "^O"}, // SI 399 {"\x0F", "^O"}, // SI
401// {"\x10", "^P"}, // DLE 400 {"\x10", "^P"}, // DLE
402// {"\x11", "^Q"}, // DC1 401 {"\x11", "^Q"}, // DC1
403// {"\x12", "^R"}, // DC2 402 {"\x12", "^R"}, // DC2
404// {"\x13", "^S"}, // DC3 403 {"\x13", "^S"}, // DC3
405// {"\x14", "^T"}, // DC4 404 {"\x14", "^T"}, // DC4
406// {"\x15", "^U"}, // NAK 405 {"\x15", "^U"}, // NAK
407// {"\x16", "^V"}, // SYN 406 {"\x16", "^V"}, // SYN
408// {"\x17", "^W"}, // ETB 407 {"\x17", "^W"}, // ETB
409// {"\x18", "^X"}, // CAN 408 {"\x18", "^X"}, // CAN
410// {"\x19", "^Y"}, // EM 409 {"\x19", "^Y"}, // EM
411// {"\x1A", "^Z"}, // SUB 410 {"\x1A", "^Z"}, // SUB
412// {"\x1B", "Esc"}, // ESC Esc key. Commented out coz it's the ANSI start byte in the above multibyte keys. Handled in the code with a timeout. 411 {"\x1B", "^["}, // ESC Esc key. Commented out coz it's the ANSI start byte in the above multibyte keys. Handled in the code with a timeout.
413// {"\x1C", "^\\"}, // FS 412 {"\x1C", "^\\"}, // FS
414// {"\x1D", "^]"}, // GS 413 {"\x1D", "^]"}, // GS
415// {"\x1E", "^^"}, // RS 414 {"\x1E", "^^"}, // RS
416// {"\x1F", "^_"}, // US 415 {"\x1F", "^_"}, // US
417 {"\x7f", "BS"}, // Backspace key, usually. Ctrl-? perhaps? 416 {"\x7f", "BS"}, // Backspace key, usually. Ctrl-? perhaps?
418 {NULL, NULL} 417 {NULL, NULL}
419}; 418};
@@ -1729,66 +1728,9 @@ void nop(box *box, event *event)
1729 // 'tis a nop, don't actually do anything. 1728 // 'tis a nop, don't actually do anything.
1730} 1729}
1731 1730
1732#define BUFFER_LEN 16
1733
1734 1731
1735int handleKey(view *view, int i, char *keyName, char *buffer)
1736{
1737 // This is using the currentBox instead of view, coz the command line keys are part of the box context now, not separate.
1738 struct keyCommand *keys = currentBox->view->content->context->modes[currentBox->view->mode].keys;
1739 int k, len = strlen(keyName), found = 0, doZero = 1;
1740
1741 for (k = 0; keys[k].key; k++)
1742 {
1743 if (strncmp(keys[k].key, keyName, len) == 0)
1744 {
1745 if ('\0' != keys[k].key[len])
1746 { // Found only a partial key.
1747 if (('^' == keyName[0]) && (1 != len)) // Want to let actual ^ characters through unmolested.
1748 { // And it's a control key combo, so keep accumulating them.
1749 // Note this wont just keep accumulating, coz the moment it no longer matches any key combos, it fails to be found and falls through.
1750 found = 1;
1751 i++;
1752 doZero = 0;
1753 break;
1754 }
1755 else // It's really an ordinary key, but we can break early at least.
1756 break;
1757 }
1758 else // We have matched the entire key name, so do it.
1759 {
1760 found = 1;
1761 doCommand(view->content->context->commands, keys[k].command, view, NULL);
1762 }
1763 break;
1764 }
1765 }
1766 if (!found) // No bound key, or partial control key combo, add input to the current view.
1767 {
1768 // TODO - Should check for tabs to, and insert them.
1769 // Though better off having a function for that?
1770 if ((i == 0) && (isprint(buffer[0])))
1771 {
1772 mooshStrings(view->line, buffer, view->iX, 0, !TT.overWriteMode);
1773 view->oW = formatLine(view, view->line->line, &(view->output));
1774 moveCursorRelative(view, strlen(buffer), 0, 0, 0);
1775 }
1776 else
1777 {
1778 // TODO - Should bitch on the status line instead.
1779 fprintf(stderr, "Key is %s\n", keyName);
1780 fflush(stderr);
1781 }
1782 }
1783 if (doZero)
1784 {
1785 i = 0;
1786 buffer[0] = '\0';
1787 }
1788
1789 return i;
1790}
1791 1732
1733#define BUFFER_LEN 16
1792 1734
1793// Basically this is the main loop. 1735// Basically this is the main loop.
1794 1736
@@ -1800,14 +1742,16 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1800{ 1742{
1801 struct termios termio, oldtermio; 1743 struct termios termio, oldtermio;
1802 struct pollfd pollfds[1]; 1744 struct pollfd pollfds[1];
1803 char buffer[BUFFER_LEN]; 1745 char buffer[BUFFER_LEN + 1];
1746 char command[BUFFER_LEN + 1];
1804 int pollcount = 1; 1747 int pollcount = 1;
1805 int i = 0; 1748 int i = 0;
1806// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down. 1749// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down.
1807// uint16_t h = 1; 1750// uint16_t h = 1;
1808// TODO - should check if it's at the top of the box, then grow it down instead of up if so. 1751// TODO - should check if it's at the top of the box, then grow it down instead of up if so.
1809 1752
1810 buffer[0] = '\0'; 1753 buffer[0] = 0;
1754 command[0] = 0;
1811 1755
1812 if (view->box) 1756 if (view->box)
1813 sizeViewToBox(view->box, X, Y, W, H); 1757 sizeViewToBox(view->box, X, Y, W, H);
@@ -1845,6 +1789,8 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1845 // TODO - We can reuse one or two of these to have less of them. 1789 // TODO - We can reuse one or two of these to have less of them.
1846 int j = 0, p, ret, y, len; 1790 int j = 0, p, ret, y, len;
1847 1791
1792 // Coz things might change out from under us, find the current view.
1793 // TODO - see if I can get this lot out of here.
1848 if (commandMode) 1794 if (commandMode)
1849 view = commandLine; 1795 view = commandLine;
1850 else 1796 else
@@ -1861,6 +1807,7 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1861 pollfds[0].events = POLLIN; 1807 pollfds[0].events = POLLIN;
1862 pollfds[0].fd = 0; 1808 pollfds[0].fd = 0;
1863 1809
1810 // TODO - Should only ask for a time out after we get an Escape.
1864 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100). 1811 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100).
1865 if (0 > p) perror_exit("poll"); 1812 if (0 > p) perror_exit("poll");
1866 if (0 == p) // A timeout, trigger a time event. 1813 if (0 == p) // A timeout, trigger a time event.
@@ -1868,24 +1815,21 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1868 if ((1 == i) && ('\x1B' == buffer[0])) 1815 if ((1 == i) && ('\x1B' == buffer[0]))
1869 { 1816 {
1870 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it. 1817 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it.
1871 strcpy(buffer, "^["); 1818 strcpy(command, "^[");
1872 i = 1; 1819 i = 0;
1873 i = handleKey(view, i, buffer, buffer); 1820 buffer[0] = 0;
1874 continue;
1875 }
1876 else
1877 {
1878 // TODO - Send a timer event somewhere.
1879 // This wont be a precise timed event, but don't think we need one.
1880 continue;
1881 } 1821 }
1822 // TODO - Send a timer event somewhere. This wont be a precise timed event, but don't think we need one.
1882 } 1823 }
1883 for (p--; 0 <= p; p--) 1824
1825 while (0 < p)
1884 { 1826 {
1827 p--;
1885 if (pollfds[p].revents & POLLIN) 1828 if (pollfds[p].revents & POLLIN)
1886 { 1829 {
1887 ret = read(pollfds[p].fd, &buffer[i], 1); 1830 // I am assuming that we get the input atomically, each multibyte key fits neatly into one read.
1888 buffer[i + 1] = '\0'; 1831 // If that's not true (which is entirely likely), then we have to get complicated with circular buffers and stuff, or just one byte at a time.
1832 ret = read(pollfds[p].fd, &buffer[i], BUFFER_LEN - i);
1889 if (ret < 0) // An error happened. 1833 if (ret < 0) // An error happened.
1890 { 1834 {
1891 // For now, just ignore errors. 1835 // For now, just ignore errors.
@@ -1896,66 +1840,84 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1896 { 1840 {
1897 fprintf(stderr, "EOF\n"); 1841 fprintf(stderr, "EOF\n");
1898 fflush(stderr); 1842 fflush(stderr);
1899 break;
1900 }
1901 else if (BUFFER_LEN == i + 1) // Ran out of buffer.
1902 {
1903 fprintf(stderr, "Full buffer -%s\n", buffer);
1904 for (j = 0; buffer[j + 1]; j++)
1905 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]);
1906 fflush(stderr);
1907 i = 0;
1908 } 1843 }
1909 else 1844 else
1910 { 1845 {
1911 char *keyName = NULL; 1846 i += ret;
1912 1847 if (BUFFER_LEN <= i) // Ran out of buffer.
1913 if (('\x1B' == buffer[i]) && (0 != i)) // An unrecognised escape sequence, start again.
1914 // TODO - it might be a reply from a query we sent, like asking for the terminal size or cursor position. Which apparently is the same thing.
1915 { 1848 {
1916 // TODO - Should bitch on the status line instead. 1849 fprintf(stderr, "Full buffer - %s -> %s\n", buffer, command);
1917 fprintf(stderr, "Unknown escape sequence ");
1918 for (j = 0; buffer[j + 1]; j++) 1850 for (j = 0; buffer[j + 1]; j++)
1919 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]); 1851 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]);
1920 fprintf(stderr, "\n");
1921 fflush(stderr); 1852 fflush(stderr);
1922 buffer[0] = '\x1B'; 1853 i = 0;
1923 i = 1; 1854 buffer[0] = 0;
1924 continue;
1925 }
1926
1927 for (j = 0; keys[j].code; j++) // Search for multibyte keys and some control keys.
1928 {
1929 if (strcmp(keys[j].code, buffer) == 0)
1930 {
1931 keyName = keys[j].name;
1932 break;
1933 }
1934 } 1855 }
1935 // See if it's an ordinary key,
1936 if ((NULL == keyName) && (0 == i) && isprint(buffer[0]))
1937 keyName = buffer;
1938 // Check for control keys, but not those that have already been identified, or ESC.
1939 if ((NULL == keyName) && iscntrl(buffer[i]) && ('\x1B' != buffer[i]))
1940 {
1941 // Convert to "^X" format.
1942 buffer[i + 1] = buffer[i] + '@';
1943 buffer[i++] = '^';
1944 buffer[i + 1] = '\0';
1945 keyName=buffer;
1946 }
1947 // See if it's already accumulating a control key combo.
1948 if ('^' == buffer[0])
1949 keyName = buffer;
1950 // For now we will assume that control keys could be the start of multi key combinations.
1951 // TODO - If the view->context HAS on event handler, use it, otherwise look up the specific event handler in the context modes ourselves?
1952 if (keyName) // Search for a bound key.
1953 i = handleKey(view, i, keyName, buffer);
1954 else 1856 else
1955 i++; 1857 buffer[i] = 0;
1956 } 1858 }
1957 } 1859 }
1958 } 1860 }
1861
1862// TODO - think vi got screwed up now. sigh
1863
1864 // For a real timeout checked Esc, buffer is now empty, so this for loop wont find it anyway.
1865 // 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.
1866 for (j = 0; keys[j].code; j++) // Search for multibyte keys and some control keys.
1867 {
1868 if (strcmp(keys[j].code, buffer) == 0)
1869 {
1870 strcat(command, keys[j].name);
1871 i = 0;
1872 buffer[0] = 0;
1873 break;
1874 }
1875 }
1876
1877 // See if it's an ordinary key,
1878 if ((1 == i) && isprint(buffer[0]))
1879 {
1880 // If there's an outstanding command, add this to the end of it.
1881 if (command[0])
1882 strcat(command, buffer);
1883 else
1884 {
1885 // TODO - Should check for tabs to, and insert them.
1886 // Though better off having a function for that?
1887 // TODO - see if I can get these out of here. Some sort of pushCharacter(buffer, blob) that is passed in.
1888 mooshStrings(view->line, buffer, view->iX, 0, !TT.overWriteMode);
1889 view->oW = formatLine(view, view->line->line, &(view->output));
1890 moveCursorRelative(view, strlen(buffer), 0, 0, 0);
1891 }
1892 i = 0;
1893 buffer[0] = 0;
1894 }
1895
1896 // TODO - If the view->context has on event handler, use it, otherwise look up the specific event handler in the context modes ourselves.
1897 if (command[0]) // Search for a bound key.
1898 {
1899 if (BUFFER_LEN <= strlen(command))
1900 {
1901 fprintf(stderr, "Full command buffer - %s \n", command);
1902 fflush(stderr);
1903 command[0] = 0;
1904 }
1905
1906 // This is using the currentBox instead of view, coz the command line keys are part of the box context now, not separate.
1907 // More importantly, the currentBox may change due to a command.
1908 struct keyCommand *ourKeys = currentBox->view->content->context->modes[currentBox->view->mode].keys;
1909
1910 for (j = 0; ourKeys[j].key; j++)
1911 {
1912 if (strcmp(ourKeys[j].key, command) == 0)
1913 {
1914 doCommand(view->content->context->commands, ourKeys[j].command, view, NULL);
1915 command[0] = 0;
1916 break;
1917 }
1918 }
1919 }
1920
1959 } 1921 }
1960 1922
1961 // Restore the old terminal settings. 1923 // Restore the old terminal settings.