diff options
author | David Walter Seikel | 2014-01-29 21:55:43 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-01-29 21:55:43 +1000 |
commit | f883185e52bbcb9fbc8ab070b03681e9250bef38 (patch) | |
tree | 6e86f751900c9d69d74a72a7915726a55b2e2477 | |
parent | Add a CSI parser. We need one for terminal sizing and mouse reports. (diff) | |
download | boxes-f883185e52bbcb9fbc8ab070b03681e9250bef38.zip boxes-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.gz boxes-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.bz2 boxes-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.xz |
Signal catcher to catch those signals sent on keystrokes.
Actually found a better way while researching this, and this all gets deleted.
I wanted to save this version in the git history though.
-rw-r--r-- | boxes.c | 78 |
1 files changed, 77 insertions, 1 deletions
@@ -32,6 +32,13 @@ config BOXES | |||
32 | Stick chars means to use ASCII for the boxes instead of "graphics" characters. | 32 | Stick chars means to use ASCII for the boxes instead of "graphics" characters. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | |||
36 | /* We need to catch some signals, coz some key strokes used by some editors trigger signals. | ||
37 | If we use poll or select, we get the race condition from the signals. | ||
38 | Poll is preferable over select in general. So I was using poll originally. | ||
39 | However, ppoll is Linux specific, and worse, needs to define the following swear words... | ||
40 | */ | ||
41 | #define _GNU_SOURCE | ||
35 | #include "toys.h" | 42 | #include "toys.h" |
36 | 43 | ||
37 | GLOBALS( | 44 | GLOBALS( |
@@ -659,6 +666,7 @@ static box *rootBox; // Parent of the rest of the boxes, or the only box. Alway | |||
659 | static box *currentBox; | 666 | static box *currentBox; |
660 | static view *commandLine; | 667 | static view *commandLine; |
661 | static int commandMode; | 668 | static int commandMode; |
669 | static /*sigatomic_t*/ volatile int signalPipe[2]; | ||
662 | 670 | ||
663 | 671 | ||
664 | #define MEM_SIZE 128 // Chunk size for line memory allocation. | 672 | #define MEM_SIZE 128 // Chunk size for line memory allocation. |
@@ -1857,7 +1865,9 @@ struct CSI CSI_terminators[] = | |||
1857 | 1865 | ||
1858 | void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command)) | 1866 | void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command)) |
1859 | { | 1867 | { |
1860 | struct pollfd pollfds[1]; | 1868 | struct pollfd pollfds[2]; |
1869 | struct timespec timeout = {0, 100000000}; // Timeout of one tenth of a second. | ||
1870 | sigset_t signalMask; | ||
1861 | // Get the initial command set. | 1871 | // Get the initial command set. |
1862 | struct keyCommand *ourKeys = lineCommand(extra, ""); | 1872 | struct keyCommand *ourKeys = lineCommand(extra, ""); |
1863 | char buffer[20], command[20], csFinal[8]; | 1873 | char buffer[20], command[20], csFinal[8]; |
@@ -1869,6 +1879,14 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key | |||
1869 | buffer[0] = 0; | 1879 | buffer[0] = 0; |
1870 | command[0] = 0; | 1880 | command[0] = 0; |
1871 | 1881 | ||
1882 | sigemptyset(&signalMask); | ||
1883 | sigaddset(&signalMask, SIGINT); | ||
1884 | sigaddset(&signalMask, SIGCONT); | ||
1885 | // sigaddset(&signalMask, SIGSTOP); | ||
1886 | // sigaddset(&signalMask, SIGINFO); | ||
1887 | sigaddset(&signalMask, SIGTSTP); | ||
1888 | sigaddset(&signalMask, SIGQUIT); | ||
1889 | |||
1872 | // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now. | 1890 | // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now. |
1873 | TT.stillRunning = 1; | 1891 | TT.stillRunning = 1; |
1874 | while (TT.stillRunning) | 1892 | while (TT.stillRunning) |
@@ -1888,11 +1906,15 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key | |||
1888 | memset(pollfds, 0, pollcount * sizeof(struct pollfd)); | 1906 | memset(pollfds, 0, pollcount * sizeof(struct pollfd)); |
1889 | pollfds[0].events = POLLIN; | 1907 | pollfds[0].events = POLLIN; |
1890 | pollfds[0].fd = 0; | 1908 | pollfds[0].fd = 0; |
1909 | pollfds[0].events = POLLIN; | ||
1910 | pollfds[0].fd = signalPipe[0]; | ||
1891 | 1911 | ||
1892 | // TODO - A bit unstable at the moment, something makes it go into a horrid CPU eating edit line flicker mode sometimes. And / or vi mode can crash on exit (stack smash). | 1912 | // TODO - A bit unstable at the moment, something makes it go into a horrid CPU eating edit line flicker mode sometimes. And / or vi mode can crash on exit (stack smash). |
1893 | // This might be fixed now. | 1913 | // This might be fixed now. |
1894 | 1914 | ||
1895 | // TODO - Should only ask for a time out after we get an Escape. | 1915 | // TODO - Should only ask for a time out after we get an Escape. |
1916 | p = ppoll(pollfds, pollcount, &timeout, &signalMask); | ||
1917 | // p = poll(pollfds, pollcount, 100); | ||
1896 | p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100). | 1918 | p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100). |
1897 | if (0 > p) perror_exit("poll"); | 1919 | if (0 > p) perror_exit("poll"); |
1898 | if (0 == p) // A timeout, trigger a time event. | 1920 | if (0 == p) // A timeout, trigger a time event. |
@@ -2756,6 +2778,35 @@ struct context simpleVi = | |||
2756 | // TODO - have any unrecognised escape key sequence start up a new box (split one) to show the "show keys" content. | 2778 | // TODO - have any unrecognised escape key sequence start up a new box (split one) to show the "show keys" content. |
2757 | // That just adds each "Key is X" to the end of the content, and allows scrolling, as well as switching between other boxes. | 2779 | // That just adds each "Key is X" to the end of the content, and allows scrolling, as well as switching between other boxes. |
2758 | 2780 | ||
2781 | struct signalTranslate | ||
2782 | { | ||
2783 | int sig; | ||
2784 | char key; | ||
2785 | }; | ||
2786 | |||
2787 | struct signalTranslate translate[] = | ||
2788 | { | ||
2789 | {SIGINT, '\x03'}, // ^C | ||
2790 | {SIGCONT, '\x11'}, // ^Q | ||
2791 | {SIGSTOP, '\x13'}, // ^S | ||
2792 | // {SIGINFO, '\x14'}, // ^T | ||
2793 | {SIGTSTP, '\x1A'}, // ^Z | ||
2794 | {SIGQUIT, '\x1C'} // "^\" | ||
2795 | }; | ||
2796 | |||
2797 | static void handleSignals(int signo) | ||
2798 | { | ||
2799 | int j; | ||
2800 | |||
2801 | for (j = 0; j < (sizeof(translate) / sizeof(*translate)); j++) | ||
2802 | { | ||
2803 | if (translate[j].sig == signo) | ||
2804 | { | ||
2805 | write(signalPipe[1], &translate[j].key, 1); | ||
2806 | break; | ||
2807 | } | ||
2808 | } | ||
2809 | } | ||
2759 | 2810 | ||
2760 | void boxes_main(void) | 2811 | void boxes_main(void) |
2761 | { | 2812 | { |
@@ -2763,6 +2814,23 @@ void boxes_main(void) | |||
2763 | struct termios termio, oldtermio; | 2814 | struct termios termio, oldtermio; |
2764 | char *prompt = "Enter a command : "; | 2815 | char *prompt = "Enter a command : "; |
2765 | unsigned W = 80, H = 24; | 2816 | unsigned W = 80, H = 24; |
2817 | int signalPipe[2]; | ||
2818 | struct sigaction sigAction, oldSigActions[6]; | ||
2819 | |||
2820 | // Set up pipes and signal handlers for catching keys that are normally signals. | ||
2821 | if (pipe(signalPipe)) perror_exit("can't open a pipe"); | ||
2822 | fcntl(signalPipe[0], F_SETFL, O_NONBLOCK); | ||
2823 | fcntl(signalPipe[1], F_SETFL, O_NONBLOCK); | ||
2824 | // Assumes that sigAction is not messed with by sigaction(). | ||
2825 | memset(&sigAction, 0, sizeof(sigAction)); | ||
2826 | sigAction.sa_handler = handleSignals; | ||
2827 | sigAction.sa_flags = SA_RESTART; // Useless since we are using poll. | ||
2828 | if (sigaction(SIGINT, &sigAction, &oldSigActions[0])) perror_exit("can't set signal handler SIGINT"); // Crashes with "poll: Interrupted system call" | ||
2829 | if (sigaction(SIGCONT, &sigAction, &oldSigActions[1])) perror_exit("can't set signal handler SIGCONT"); // Not needed it seems. | ||
2830 | // if (sigaction(SIGSTOP, &sigAction, &oldSigActions[2])) perror_exit("can't set signal handler SIGSTOP"); // Can't be done, screw emacs and vi. "can't set signal handler SIGSTOP: Invalid argument" | ||
2831 | // if (sigaction(SIGINFO, &sigAction, &oldSigActions[3])) perror_exit("can't set signal handler SIGINFO"); // No such thing as SIGINFO without special foo. | ||
2832 | if (sigaction(SIGTSTP, &sigAction, &oldSigActions[4])) perror_exit("can't set signal handler SIGTSTP"); // Crashes with "poll: Interrupted system call" | ||
2833 | if (sigaction(SIGQUIT, &sigAction, &oldSigActions[5])) perror_exit("can't set signal handler SIGQUIT"); // Crashes with "poll: Interrupted system call" if using "^\" | ||
2766 | 2834 | ||
2767 | // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead. | 2835 | // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead. |
2768 | if (toys.optflags & FLAG_m) | 2836 | if (toys.optflags & FLAG_m) |
@@ -2866,6 +2934,14 @@ void boxes_main(void) | |||
2866 | // Restore the old terminal settings. | 2934 | // Restore the old terminal settings. |
2867 | tcsetattr(0, TCSANOW, &oldtermio); | 2935 | tcsetattr(0, TCSANOW, &oldtermio); |
2868 | 2936 | ||
2937 | // Probaly don't need to restore these before quitting, but including this in the example. | ||
2938 | sigaction(SIGINT, &oldSigActions[0], NULL); | ||
2939 | sigaction(SIGCONT, &oldSigActions[1], NULL); | ||
2940 | // sigaction(SIGSTOP, &oldSigActions[2], NULL); | ||
2941 | // sigaction(SIGINFO, &oldSigActions[3], NULL); | ||
2942 | sigaction(SIGTSTP, &oldSigActions[4], NULL); | ||
2943 | sigaction(SIGQUIT, &oldSigActions[5], NULL); | ||
2944 | |||
2869 | puts("\n"); | 2945 | puts("\n"); |
2870 | fflush(stdout); | 2946 | fflush(stdout); |
2871 | } | 2947 | } |