⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 screen.cc

📁 Unix下的MUD客户端程序
💻 CC
字号:
// The Screen class is a derivative of Window that writes the resulting// data onto the physical screen#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <sys/uio.h>#include <sys/socket.h> // Some libc/linux versions seem to have iovec there :(#include "mcl.h"#include "cui.h"#include "Buffer.h"#include "Curses.h"#include "Session.h"// This isn't too prettyint get_screen_size_x(){	// Screen dimensions	struct winsize size;	if (ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) &size) < 0)		error ("get_screen_size:ioctl:%m");	return size.ws_col;		}int get_screen_size_y(){	// Screen dimensions	struct winsize size;	if (ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) &size) < 0)		error ("get_screen_size:ioctl:%m");	return size.ws_row;		}				// Initialization. Figure out what dimensions we have here Screen::Screen() : Window(NULL, get_screen_size_x(), get_screen_size_y()), fd(0) {    // Open our fd    char *tty = ttyname(STDIN_FILENO);    int ttyno;    char buf[256];    usingVirtual = true;    if (1 == (sscanf(tty, "/dev/tty%d", &ttyno))) {        sprintf (buf, "/dev/vcsa%d", ttyno);                if ((fd = open (buf, O_WRONLY)) < 0) {            fprintf (stderr, "\nFailed to open %s: %m. \nPerhaps your permissions are wrong?\n\n", buf);            exit (EXIT_FAILURE);        }    } else {        usingVirtual = false;        scr_x = scr_y = scr_w = scr_h = 0;        last_screen = new attrib[width * height];        memcpy(last_screen, canvas, width * height * sizeof(attrib));        write(STDOUT_FILENO, CLEAR_SCREEN, strlen(CLEAR_SCREEN));        out = new Buffer(32000);    }    init_curses(usingVirtual);}// Refresh the screenbool Screen::refreshVirtual() {    unsigned char cursor_pos[2];        struct iovec write_struct[2] =    {        {(__ptr_t) &cursor_pos,	2},        {(__ptr_t) canvas,		width*height*sizeof(*canvas)}    };        if (dirty)        clear();        if (Window::refresh())    {                lseek(fd,2,SEEK_SET);	// Go to beginning of the vcsa, but not the first        // 2 bytes which are selection pos or somethign                // Write cursor position, then canvas data to the device                cursor_pos[0] = cursor_x;        cursor_pos[1] = cursor_y;                while (writev (fd, write_struct, 2) < 0)            if (errno != EINTR && errno != EAGAIN)                error ("Screen::refresh():writev");                return true;    }    else        return false;}bool Screen::refresh() {    if (usingVirtual)        return refreshVirtual();    else        return refreshTTY();}// Why this?// ANSI colors and the colors used by /dev/vcsa do not fit together// Internally we use the /dev/vcsa colors so we must translate herestatic int reverse_color_conv_table[8] =  {    0,4,2,6,1,5,3,7};// 8-bit CSI - use this if your terminal supports it!// #define CSI "\x9B"// 7-bit CSI#define CSI "\e["// TODO: split it up so we can change fg and bg seperatelyconst char* Screen::getColorCode (int color, bool setBackground) const {    int fg_color = 30 + reverse_color_conv_table[color & 0x07];    int bold = color & fg_bold;    int bg_color = 40 + reverse_color_conv_table[color >> 4];    static char buf[64];        // Xterm doesn't like fg_white|bg_black ?!    if (fg_color == 37 &&  bg_color == 40 && !bold)        sprintf(buf, CSI "0m");    else {        char bg[8];        if (setBackground)            sprintf(bg, "%d;", bg_color);        else            bg[0] = NUL;                if (bold)            sprintf(buf, CSI "1;%s%dm", bg, fg_color);        else            sprintf(buf, CSI "0;%s%dm", bg, fg_color);    }    return buf;}void Screen::setTTYColor(int color, bool setBackground) {    const char *code = getColorCode(color, setBackground);    globalStats.ctrl_chars += out->strcat(code);}// Print a single character. If it's a graphical character, and ACS is not yet enabled it, enable itvoid Screen::printCharacter(int c, bool& acs_enabled) {    if (c >= SC_BASE && c < SC_END && smacs) {        if (!acs_enabled)            out->strcat(smacs);        out->chrcat(real_special_chars[c-SC_BASE]);        acs_enabled = true;    } else {        if (acs_enabled && rmacs) {            out->strcat(rmacs);            acs_enabled = false;        }        out->chrcat(c);    }}// This is Y,X, both starting at 1#define VT_GOTO CSI "%d;%dH"// goes to 1,1#define VT_HOME CSI "H" #define MAX_SCROLL_TRY 5// some more optimization could be useful here!// Checksum rows? (could error)// do a memcp before running through it?// probably not worth it, it's the output that's most importantbool Screen::refreshTTY() {    int x,y;    bool acs_enabled = false;        if (Window::refresh()) {                // let's go with a very raw refresh for now        out->clear();        // how many lines are different?        int diff = 0;        for (y = 0; y < height; y++)            if (memcmp(last_screen+y*width, canvas+y*width, width * sizeof(attrib)) != 0)                diff++;                // Figure out whether we can scroll the scrolling region        // Note that it isn't always a win.. when e.g. the alt-o window is open for example, how to evaluate?        if (scr_h && diff > width/2) {            int scrreg_bottom = scr_y + scr_h - 1; // the last line of the scrolling region            int scrreg_test_start = scr_y + 5; // Where do we start looking to determine scroll happened?            int scrreg_test_end =  scrreg_test_start + MAX_SCROLL_TRY;                        // find out where the saved line at the bottom of the scrreg has went to            for (y = scrreg_test_start; y <= scrreg_test_end ; y++)                if (memcmp(last_screen + scrreg_test_end*width, canvas + y*width, width * sizeof(attrib)) == 0) {                    int lines = scrreg_test_end - y;                    if (lines > 0) {                        // adjust to what we think the screen looks like                        memmove(last_screen + scr_y*width, last_screen+ ((scr_y+lines)*width), (scr_h - lines) * width * sizeof(attrib));                                                                                // mark the black that should now appear at the bottom there                        for (y = scrreg_bottom - lines; y <= scrreg_bottom; y++)                            memcpy(last_screen + y*width, clearLine, width * sizeof(attrib));                                                setTTYColor(bg_black|fg_white, true); // we want to scroll up black space                        globalStats.ctrl_chars += out->printf(CSI "%d;%dr", scr_y+1, scr_y+scr_h);                        globalStats.ctrl_chars += out->printf(VT_GOTO, scr_y+scr_h, 1);                        while (lines-- > 0)                            out->strcat("\n");                        globalStats.ctrl_chars += out->printf(CSI "%d;%dr", 1, height);                    }                    break;                }        }                out->printf(VT_HOME); // top left corner                int saved_color = -1;        int last_y = 0, last_x = 0;        for (y = 0; y < height ; y++) {            for (x = 0; x < width; x++) {                // don't write in that very last cell                if (y == height-1 && x == width-1)                    continue;                                int offset = x + y * width;                if (canvas[offset] != last_screen[offset]) {                    int color = canvas[offset] >> 8;                    int c = canvas[offset] & 0xFF;                    if (color != saved_color) {                        // XTerm seems to have problems with this?!#if 0                        setTTYColor(color, color >> 4 != saved_color >> 4);#endif                        setTTYColor(color, true);                        saved_color = color;                    }                    // Are we there yet?                    if (x != last_x || y != last_y) {                        // It is  more efficient to just print the actual skipped character in some                        // cases rather than goto (especially when it's e.g. a space in our current color)                        if (last_y == y && last_x == x-1 && (canvas[offset-1] >> 8) == saved_color)                            printCharacter(canvas[offset-1] & 0xFF, acs_enabled);                        else {                            // just on the line above? then we can just send a newline to go down#if 0                            if (x == 0 && last_y == y-1)                                out->printf("\r\n");                            else#endif                                globalStats.ctrl_chars += out->printf(VT_GOTO, y+1, x+1);                        }                    }                                        last_y = y;                    last_x = x+1;                    if (last_x == width) {                        last_x = 0;                        last_y++;                    }                                        if (c >= 32)                        printCharacter(c, acs_enabled);                    else                        out->chrcat(' ');                }            }        }                globalStats.ctrl_chars += out->printf(VT_GOTO, cursor_y+1, cursor_x+1); // top left corner        if (rmacs && acs_enabled) // Always reset JIC            globalStats.ctrl_chars += out->strcat(rmacs);                        int n = write(STDIN_FILENO, ~*out, out->count());        if (n != out->count())            abort();                memcpy(last_screen, canvas, width*height*sizeof(attrib));                globalStats.tty_chars += out->count();                return true;    } else        return false;    }Screen::~Screen() {    if (usingVirtual)        close (fd);}void Screen::set_cursor(int _x, int _y) {	cursor_x = _x;	cursor_y = _y;}void Screen::setScrollingRegion(int x, int y, int w, int h) {    scr_x = x; scr_y = y; scr_w = w; scr_h = h;}void Screen::flash() {	if (config->getOption(opt_beep))		write (STDIN_FILENO, "\a",1);}bool Screen::keypress(int key) {    // Check for alt-X    if (key >= key_alt_1 && key < key_alt_9)  {        Window *w = Numbered::find(key-key_alt_1+1);        if (w)        {            w->show(true);            w->popUp();            return true;        }    }    else if (key == key_ctrl_l) { // redraw        if (!usingVirtual)            memset(last_screen, 0, width*height*sizeof(attrib));        return true;    }        if (!Window::keypress(key))        if (!currentSession || !currentSession->expand_macros(key))            status->setf ("Keycode %d (%s) was not handled by any object", key, key_name(key));    return true;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -