This is a maintenance fork
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.6 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #if 0
  2. /*─────────────────────────────────────────────────────────────────╗
  3. To the extent possible under law, Justine Tunney has waived
  4. all copyright and related or neighboring rights to this file,
  5. as it is written in the following disclaimers:
  6. http://unlicense.org/ │
  7. http://creativecommons.org/publicdomain/zero/1.0/ │
  8. */
  9. #endif
  10. #include "dsp/tty/tty.h"
  11. #include "libc/calls/calls.h"
  12. #include "libc/calls/ioctl.h"
  13. #include "libc/calls/struct/sigaction.h"
  14. #include "libc/calls/termios.h"
  15. #include "libc/errno.h"
  16. #include "libc/fmt/fmt.h"
  17. #include "libc/log/check.h"
  18. #include "libc/log/log.h"
  19. #include "libc/runtime/runtime.h"
  20. #include "libc/stdio/stdio.h"
  21. #include "libc/str/str.h"
  22. #include "libc/sysv/consts/exit.h"
  23. #include "libc/sysv/consts/fileno.h"
  24. #include "libc/sysv/consts/o.h"
  25. #include "libc/sysv/consts/sig.h"
  26. #include "libc/sysv/consts/termios.h"
  27. #include "libc/x/x.h"
  28. #define CTRL(C) ((C) ^ 0b01000000)
  29. #define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
  30. #define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
  31. #define PROBE_DISPLAY_SIZE "\e7\e[9979;9979H\e[6n\e8"
  32. char code[512];
  33. struct winsize wsize;
  34. struct termios oldterm;
  35. volatile bool resized, killed;
  36. void onresize(void) {
  37. resized = true;
  38. }
  39. void onkilled(int sig) {
  40. killed = true;
  41. }
  42. void restoretty(void) {
  43. write(1, DISABLE_MOUSE_TRACKING, strlen(DISABLE_MOUSE_TRACKING));
  44. ioctl(1, TCSETS, &oldterm);
  45. }
  46. int rawmode(void) {
  47. static bool once;
  48. struct termios t;
  49. if (!once) {
  50. if (ioctl(1, TCGETS, &oldterm) != -1) {
  51. atexit(restoretty);
  52. } else {
  53. return -1;
  54. }
  55. once = true;
  56. }
  57. memcpy(&t, &oldterm, sizeof(t));
  58. t.c_cc[VMIN] = 1;
  59. t.c_cc[VTIME] = 1;
  60. t.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON |
  61. IGNBRK | BRKINT);
  62. t.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL | ISIG);
  63. t.c_cflag &= ~(CSIZE | PARENB);
  64. t.c_oflag &= ~OPOST;
  65. t.c_cflag |= CS8;
  66. t.c_iflag |= IUTF8;
  67. ioctl(1, TCSETS, &t);
  68. write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING));
  69. write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE));
  70. return 0;
  71. }
  72. void getsize(void) {
  73. if (getttysize(1, &wsize) != -1) {
  74. printf("termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
  75. wsize.ws_row);
  76. } else {
  77. printf("%s\n", strerror(errno));
  78. }
  79. }
  80. const char *describemouseevent(int e) {
  81. static char buf[64];
  82. buf[0] = 0;
  83. if (e & 0x10) {
  84. strcat(buf, " ctrl");
  85. }
  86. if (e & 0x40) {
  87. strcat(buf, " wheel");
  88. if (e & 0x01) {
  89. strcat(buf, " down");
  90. } else {
  91. strcat(buf, " up");
  92. }
  93. } else {
  94. switch (e & 3) {
  95. case 0:
  96. strcat(buf, " left");
  97. break;
  98. case 1:
  99. strcat(buf, " middle");
  100. break;
  101. case 2:
  102. strcat(buf, " right");
  103. break;
  104. default:
  105. unreachable;
  106. }
  107. if (e & 0x20) {
  108. strcat(buf, " drag");
  109. } else if (e & 0x04) {
  110. strcat(buf, " up");
  111. } else {
  112. strcat(buf, " down");
  113. }
  114. }
  115. return buf + 1;
  116. }
  117. int main(int argc, char *argv[]) {
  118. int e, c, y, x, n, yn, xn;
  119. xsigaction(SIGTERM, onkilled, 0, 0, NULL);
  120. xsigaction(SIGWINCH, onresize, 0, 0, NULL);
  121. xsigaction(SIGCONT, onresize, 0, 0, NULL);
  122. rawmode();
  123. getsize();
  124. while (!killed) {
  125. if (resized) {
  126. printf("SIGWINCH ");
  127. getsize();
  128. resized = false;
  129. }
  130. if ((n = readansi(0, code, sizeof(code))) == -1) {
  131. if (errno == EINTR) continue;
  132. printf("ERROR: READ: %s\r\n", strerror(errno));
  133. exit(1);
  134. }
  135. printf("%`'.*s ", n, code);
  136. if (iscntrl(code[0]) && !code[1]) {
  137. printf("is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
  138. if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
  139. } else if (startswith(code, "\e[") && endswith(code, "R")) {
  140. yn = 1, xn = 1;
  141. sscanf(code, "\e[%d;%dR", &yn, &xn);
  142. printf("inband signalling says terminal size is %d×%d\r\n", xn, yn);
  143. } else if (startswith(code, "\e[<") &&
  144. (endswith(code, "m") || endswith(code, "M"))) {
  145. e = 0, y = 1, x = 1;
  146. sscanf(code, "\e[<%d;%d;%d%c", &e, &y, &x, &c);
  147. printf("mouse %s at %d×%d\r\n", describemouseevent(e | (c == 'm') << 2),
  148. x, y);
  149. } else {
  150. printf("\r\n");
  151. }
  152. }
  153. return 0;
  154. }