Xurses...
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.

187 lines
5.1KB

  1. /*
  2. * Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
  3. *
  4. * Xurses is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
  5. * And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
  6. * It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
  7. */
  8. #ifndef XURSES_SOURCE
  9. #define XURSES_SOURCE
  10. #include <xolatile/xurses.h>
  11. int curses_active = 1;
  12. int curses_cursor = 0;
  13. char curses_signal = '\0';
  14. int curses_screen_width = 0;
  15. int curses_screen_height = 0;
  16. int curses_screen_size = 0;
  17. char * curses_screen = NULL;
  18. void (* curses_action ['~' - ' ']) (void) = { 0 };
  19. struct termios curses_old_terminal;
  20. struct termios curses_new_terminal;
  21. void curses_initialize (void) {
  22. char key;
  23. struct winsize screen_dimension;
  24. fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "[!] ioctl: Failed to get terminal size.");
  25. curses_screen_width = (int) screen_dimension.ws_col;
  26. curses_screen_height = (int) screen_dimension.ws_row;
  27. fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "[!] tcgetattr: Failed to get terminal attributes.");
  28. curses_new_terminal = curses_old_terminal;
  29. curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
  30. curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;
  31. curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  32. curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
  33. curses_new_terminal.c_cflag |= (unsigned int) (CS8);
  34. curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);
  35. fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "[!] tcsetattr: Failed to set raw terminal attributes.");
  36. curses_screen = allocate (12 * (curses_screen_width + 2) * curses_screen_height + 8);
  37. for (key = ' '; key != '~'; ++key) {
  38. curses_unbind (key);
  39. }
  40. }
  41. void curses_deinitialize (void) {
  42. curses_screen = deallocate (curses_screen);
  43. out ("\033[2J\033[H", 7);
  44. fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "[!] tcsetattr: Failed to set terminal attributes.");
  45. }
  46. void curses_synchronize (void) {
  47. curses_signal = '\0';
  48. out (curses_screen, curses_screen_size);
  49. in (& curses_signal, 1);
  50. curses_screen_size = 0;
  51. if ((curses_signal >= ' ') && (curses_signal <= '~')) {
  52. curses_action [curses_signal - ' '] ();
  53. }
  54. string_copy_limit (& curses_screen [curses_screen_size], "\033[H", 3);
  55. curses_screen_size += 3;
  56. }
  57. void curses_blank (void) {
  58. int i, j;
  59. for (i = 0; i != curses_screen_height; ++i) {
  60. for (j = 0; j != curses_screen_width; ++j) {
  61. curses_character (' ', EFFECT_NORMAL, COLOUR_WHITE, j, i);
  62. }
  63. }
  64. }
  65. void curses_character (char character, int effect, int colour, int x, int y) {
  66. char format [13] = "\033[ ;3 m \033[0m";
  67. format [2] = (char) effect + '0';
  68. format [5] = (char) colour + '0';
  69. format [7] = character;
  70. string_copy_limit (& curses_screen [(y * (curses_screen_width + 2) + x) * 12 + 3], format, 12);
  71. curses_screen_size += 12;
  72. }
  73. void curses_append_character (char character, int effect, int colour) {
  74. char format [13] = "\033[ ;3 m \033[0m";
  75. format [2] = (char) effect + '0';
  76. format [5] = (char) colour + '0';
  77. format [7] = character;
  78. string_copy_limit (& curses_screen [curses_screen_size], format, 12);
  79. curses_screen_size += 12;
  80. }
  81. void curses_append_string (char * string, int effect, int colour, int length) {
  82. char format [8] = "\033[ ;3 m";
  83. format [2] = (char) effect + '0';
  84. format [5] = (char) colour + '0';
  85. string_copy_limit (& curses_screen [curses_screen_size], format, 7);
  86. curses_screen_size += 7;
  87. string_copy_limit (& curses_screen [curses_screen_size], string, length);
  88. curses_screen_size += length;
  89. string_copy_limit (& curses_screen [curses_screen_size], "\033[0m", 4);
  90. curses_screen_size += 4;
  91. }
  92. void curses_append_cursor (int cursor_x, int cursor_y) {
  93. char format [11] = "\033[000;000H";
  94. format [4] = (char) (cursor_y / 1) % 10 + '0';
  95. format [3] = (char) (cursor_y / 10) % 10 + '0';
  96. format [2] = (char) (cursor_y / 100) % 10 + '0';
  97. format [8] = (char) (cursor_x / 1) % 10 + '0';
  98. format [7] = (char) (cursor_x / 10) % 10 + '0';
  99. format [6] = (char) (cursor_x / 100) % 10 + '0';
  100. string_copy_limit (& curses_screen [curses_screen_size], format, 10);
  101. curses_screen_size += 10;
  102. }
  103. void curses_style (int effect, int colour) {
  104. char format [8] = "\033[ ;3 m";
  105. if ((effect == -1) || (colour == -1)) {
  106. out ("\033[0m", 4);
  107. } else {
  108. format [2] = (char) effect + '0';
  109. format [5] = (char) colour + '0';
  110. out (format, 7);
  111. }
  112. }
  113. void curses_clear (void) {
  114. out ("\033[2J", 4);
  115. }
  116. void curses_show_cursor (int show) {
  117. if (show != 0) {
  118. out ("\033[?25h", 6);
  119. } else {
  120. out ("\033[?25l", 6);
  121. }
  122. }
  123. void curses_bind (char key, void (* action) (void)) {
  124. curses_action [key - ' '] = action;
  125. }
  126. void curses_unbind (char key) {
  127. curses_action [key - ' '] = curses_idle;
  128. }
  129. void curses_idle (void) {
  130. return;
  131. }
  132. void curses_exit (void) {
  133. curses_active = 0;
  134. }
  135. #endif