2023-08-28 18:52:28 -04:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
|
|
|
|
*
|
|
|
|
* Xurses is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
|
|
|
|
* 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.
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef XURSES_SOURCE
|
|
|
|
#define XURSES_SOURCE
|
|
|
|
|
|
|
|
#include <xolatile/xurses.h>
|
|
|
|
|
|
|
|
int curses_active = 1;
|
|
|
|
int curses_cursor = 0;
|
2023-09-18 16:17:08 -04:00
|
|
|
char curses_signal = '\0';
|
2023-08-28 18:52:28 -04:00
|
|
|
int curses_screen_width = 0;
|
|
|
|
int curses_screen_height = 0;
|
|
|
|
int curses_screen_size = 0;
|
|
|
|
char * curses_screen = NULL;
|
|
|
|
|
|
|
|
void (* curses_action ['~' - ' ']) (void) = { 0 };
|
|
|
|
|
|
|
|
struct termios curses_old_terminal;
|
|
|
|
struct termios curses_new_terminal;
|
|
|
|
|
|
|
|
void curses_initialize (void) {
|
|
|
|
char key;
|
|
|
|
|
|
|
|
struct winsize screen_dimension;
|
|
|
|
|
|
|
|
fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "[!] ioctl: Failed to get terminal size.");
|
|
|
|
|
|
|
|
curses_screen_width = (int) screen_dimension.ws_col;
|
|
|
|
curses_screen_height = (int) screen_dimension.ws_row;
|
|
|
|
|
|
|
|
fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "[!] tcgetattr: Failed to get terminal attributes.");
|
|
|
|
|
|
|
|
curses_new_terminal = curses_old_terminal;
|
|
|
|
|
|
|
|
curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
|
|
|
|
curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;
|
|
|
|
|
|
|
|
curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
|
|
|
curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
|
|
|
|
curses_new_terminal.c_cflag |= (unsigned int) (CS8);
|
|
|
|
curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);
|
|
|
|
|
|
|
|
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "[!] tcsetattr: Failed to set raw terminal attributes.");
|
|
|
|
|
2023-09-18 16:17:08 -04:00
|
|
|
curses_screen = allocate (12 * (curses_screen_width + 2) * curses_screen_height + 8);
|
2023-08-28 18:52:28 -04:00
|
|
|
|
|
|
|
for (key = ' '; key != '~'; ++key) {
|
|
|
|
curses_unbind (key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_deinitialize (void) {
|
2023-09-18 16:17:08 -04:00
|
|
|
curses_screen = deallocate (curses_screen);
|
2023-08-28 18:52:28 -04:00
|
|
|
|
|
|
|
out ("\033[2J\033[H", 7);
|
|
|
|
|
|
|
|
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "[!] tcsetattr: Failed to set terminal attributes.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_synchronize (void) {
|
2023-09-18 16:17:08 -04:00
|
|
|
curses_signal = '\0';
|
2023-08-28 18:52:28 -04:00
|
|
|
|
2023-09-18 16:17:08 -04:00
|
|
|
out (curses_screen, curses_screen_size);
|
2023-08-28 18:52:28 -04:00
|
|
|
|
|
|
|
in (& curses_signal, 1);
|
|
|
|
|
2023-09-18 16:17:08 -04:00
|
|
|
curses_screen_size = 0;
|
|
|
|
|
|
|
|
if ((curses_signal >= ' ') && (curses_signal <= '~')) {
|
2023-08-28 18:52:28 -04:00
|
|
|
curses_action [curses_signal - ' '] ();
|
|
|
|
}
|
2023-09-18 16:17:08 -04:00
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], "\033[H", 3);
|
|
|
|
curses_screen_size += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_blank (void) {
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i != curses_screen_height; ++i) {
|
|
|
|
for (j = 0; j != curses_screen_width; ++j) {
|
|
|
|
curses_character (' ', EFFECT_NORMAL, COLOUR_WHITE, j, i);
|
|
|
|
}
|
|
|
|
}
|
2023-08-28 18:52:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void curses_character (char character, int effect, int colour, int x, int y) {
|
2023-09-18 16:17:08 -04:00
|
|
|
char format [13] = "\033[ ;3 m \033[0m";
|
2023-08-28 18:52:28 -04:00
|
|
|
|
|
|
|
format [2] = (char) effect + '0';
|
|
|
|
format [5] = (char) colour + '0';
|
|
|
|
format [7] = character;
|
|
|
|
|
2023-09-18 16:17:08 -04:00
|
|
|
string_copy_limit (& curses_screen [(y * (curses_screen_width + 2) + x) * 12 + 3], format, 12);
|
|
|
|
|
|
|
|
curses_screen_size += 12;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_append_character (char character, int effect, int colour) {
|
|
|
|
char format [13] = "\033[ ;3 m \033[0m";
|
|
|
|
|
|
|
|
format [2] = (char) effect + '0';
|
|
|
|
format [5] = (char) colour + '0';
|
|
|
|
format [7] = character;
|
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], format, 12);
|
|
|
|
|
|
|
|
curses_screen_size += 12;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_append_string (char * string, int effect, int colour, int length) {
|
|
|
|
char format [8] = "\033[ ;3 m";
|
|
|
|
|
|
|
|
format [2] = (char) effect + '0';
|
|
|
|
format [5] = (char) colour + '0';
|
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], format, 7);
|
|
|
|
curses_screen_size += 7;
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], string, length);
|
|
|
|
curses_screen_size += length;
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], "\033[0m", 4);
|
|
|
|
curses_screen_size += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_append_cursor (int cursor_x, int cursor_y) {
|
|
|
|
char format [11] = "\033[000;000H";
|
|
|
|
|
|
|
|
format [4] = (char) (cursor_y / 1) % 10 + '0';
|
|
|
|
format [3] = (char) (cursor_y / 10) % 10 + '0';
|
|
|
|
format [2] = (char) (cursor_y / 100) % 10 + '0';
|
|
|
|
format [8] = (char) (cursor_x / 1) % 10 + '0';
|
|
|
|
format [7] = (char) (cursor_x / 10) % 10 + '0';
|
|
|
|
format [6] = (char) (cursor_x / 100) % 10 + '0';
|
|
|
|
|
|
|
|
string_copy_limit (& curses_screen [curses_screen_size], format, 10);
|
|
|
|
curses_screen_size += 10;
|
2023-08-28 18:52:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void curses_style (int effect, int colour) {
|
|
|
|
char format [8] = "\033[ ;3 m";
|
|
|
|
|
|
|
|
if ((effect == -1) || (colour == -1)) {
|
|
|
|
out ("\033[0m", 4);
|
|
|
|
} else {
|
|
|
|
format [2] = (char) effect + '0';
|
|
|
|
format [5] = (char) colour + '0';
|
|
|
|
|
|
|
|
out (format, 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_clear (void) {
|
|
|
|
out ("\033[2J", 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_show_cursor (int show) {
|
|
|
|
if (show != 0) {
|
|
|
|
out ("\033[?25h", 6);
|
|
|
|
} else {
|
|
|
|
out ("\033[?25l", 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_bind (char key, void (* action) (void)) {
|
|
|
|
curses_action [key - ' '] = action;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_unbind (char key) {
|
|
|
|
curses_action [key - ' '] = curses_idle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_idle (void) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void curses_exit (void) {
|
|
|
|
curses_active = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|