diff options
Diffstat (limited to 'cursor.cpp')
-rw-r--r-- | cursor.cpp | 1477 |
1 files changed, 1477 insertions, 0 deletions
diff --git a/cursor.cpp b/cursor.cpp new file mode 100644 index 0000000..1dde81a --- /dev/null +++ b/cursor.cpp @@ -0,0 +1,1477 @@ +// cursor.cpp +// Revision 24-apr-2009 + +#include "cursor.h" + +#include "blassic.h" + +#include "key.h" +#include "util.h" +#include "error.h" +#include "showerror.h" + +#include "trace.h" + +#include <iostream> +using std::cerr; +using std::endl; + +#include <map> +#include <queue> +#include <sstream> + +#include <string.h> + +#ifdef BLASSIC_USE_WINDOWS + + +#include <windows.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG +#include <io.h> +#endif + + +#else + + +#include <unistd.h> +#include <fcntl.h> +#include <sys/poll.h> +#include <errno.h> +#include <cassert> +#define ASSERT assert + +#include <termios.h> + +// We check for terminfo only if not in windows, +// use windows console functions even in Cygwin. + +// Now curses can be disabled from configure. +#ifndef BLASSIC_CONFIG_NO_CURSES + +#ifdef BLASSIC_CONFIG_USE_NCURSES + +#include <ncurses.h> + +#elif defined BLASSIC_CONFIG_USE_CURSES + +#include <curses.h> + +#else + +#error Bad configuration of curses options. + +#endif + +#ifdef HAVE_TERM_H +// I suppose that if this is not availabe, then is not required. +#include <term.h> +#endif + +#define BLASSIC_USE_TERMINFO + +// curses can define erase as macro, invalidating string::erase. +#ifdef erase +#undef erase +#endif +// curses can define bool as macro. +#ifdef bool +#undef bool +#endif + +#endif + + +// Stuff needed by getwidth + +#include <sys/ioctl.h> +#include <termios.h> + +// This is from ncurses. +#ifdef TIOCGSIZE +# define IOCTL_WINSIZE TIOCGSIZE +# define STRUCT_WINSIZE struct ttysize +# define WINSIZE_ROWS(n) (int)n.ts_lines +# define WINSIZE_COLS(n) (int)n.ts_cols +#else +# ifdef TIOCGWINSZ +# define IOCTL_WINSIZE TIOCGWINSZ +# define STRUCT_WINSIZE struct winsize +# define WINSIZE_ROWS(n) (int)n.ws_row +# define WINSIZE_COLS(n) (int)n.ws_col +# endif +#endif + +#endif + +#include <iostream> +#include <map> + +using util::touch; + + +namespace { + +using namespace cursor; + + +#ifndef BLASSIC_USE_WINDOWS + +#ifdef BLASSIC_USE_TERMINFO + +bool fInit= true; + +int background= 8; + +const char + * strKeypadXmit= NULL, * strKeypadLocal= NULL, + * strCls= NULL, * strCup= NULL, + * strCursorNormal= NULL, * strCursorInvisible= NULL, + * strForeground= NULL, * strBackground= NULL, + * strEnterBold= NULL, * strExitBold= NULL, + * strMoveForward= NULL, * strMoveBack= NULL, + * strMoveForwardN= NULL, * strMoveBackN= NULL, + * strMoveUp= NULL, * strMoveDown= NULL, + * strMoveUpN= NULL, * strMoveDownN= NULL, + * strSaveCursorPos= NULL, * strRestoreCursorPos= NULL, + * strBell= NULL; + +const char * newstr (const char * str) +{ + if (str == NULL) + return NULL; + size_t l= strlen (str); + char *n= new char [l + 1]; + strcpy (n, str); + return n; +} + +inline const char * calltigetstr (const char * id) +{ + #ifdef BLASSIC_CONFIG_USE_NCURSES + const char * str= tigetstr ( (char *) id); + #else + char buffer [128]; + char * area= buffer; + const char * str= tgetstr (const_cast <char *> (id), & area); + #endif + if (str == (char *) -1) + return NULL; + return str; +} + +inline const char * mytigetstr (const char * id) +{ + return newstr (calltigetstr (id) ); +} + +int putfunc (int ic) +{ + char c= ic; + write (STDOUT_FILENO, & c, 1); + return c; +} + +inline void calltputs (const char * str) +{ + if (str != NULL) + tputs (str, 1, putfunc); +} + +inline void calltparm (const char * str, int n) +{ + if (str != NULL) + { + #ifdef BLASSIC_CONFIG_USE_NCURSES + calltputs (tparm ( (char *) str, n) ); + #else + calltputs (tgoto ( (char *) str, n, 0) ); + #endif + } +} + +void initkeytable (); + +struct str_terminfo { + const char * & str; + const char * tinfoname; + str_terminfo (const char * & str, const char * tinfoname) : + str (str), tinfoname (tinfoname) + { } +}; + +#ifdef BLASSIC_CONFIG_USE_NCURSES + +const str_terminfo strinfo []= { + str_terminfo (strKeypadXmit, "smkx"), + str_terminfo (strKeypadLocal, "rmkx"), + + str_terminfo (strCls, "clear" ), + str_terminfo (strCup, "cup" ), + + str_terminfo (strCursorNormal, "cnorm" ), + str_terminfo (strCursorInvisible, "civis" ), + + str_terminfo (strForeground, "setaf" ), + str_terminfo (strBackground, "setab" ), + + str_terminfo (strEnterBold, "bold" ), + str_terminfo (strExitBold, "sgr0" ), + + str_terminfo (strMoveForward, "cuf1" ), + str_terminfo (strMoveBack, "cub1" ), + str_terminfo (strMoveForwardN, "cuf" ), + str_terminfo (strMoveBackN, "cub" ), + str_terminfo (strMoveUp, "cuu1" ), + str_terminfo (strMoveDown, "cud1" ), + str_terminfo (strMoveUpN, "cuu" ), + str_terminfo (strMoveDownN, "cud" ), + + str_terminfo (strSaveCursorPos, "sc" ), + str_terminfo (strRestoreCursorPos, "rc" ), + + str_terminfo (strBell, "bel"), +}; + +#else + +const str_terminfo strinfo []= { + str_terminfo (strKeypadXmit, "ks"), + str_terminfo (strKeypadLocal, "ke"), + + str_terminfo (strCls, "cl" ), + str_terminfo (strCup, "cm" ), + + str_terminfo (strCursorNormal, "ve" ), + str_terminfo (strCursorInvisible, "vi" ), + + str_terminfo (strForeground, "AF" ), + str_terminfo (strBackground, "AB" ), + + str_terminfo (strEnterBold, "md" ), + str_terminfo (strExitBold, "me" ), + + str_terminfo (strMoveForward, "nd" ), + str_terminfo (strMoveBack, "le" ), + str_terminfo (strMoveForwardN, "RI" ), + str_terminfo (strMoveBackN, "LE" ), + str_terminfo (strMoveUp, "up" ), + str_terminfo (strMoveDown, "do" ), + str_terminfo (strMoveUpN, "UP" ), + str_terminfo (strMoveDownN, "DO" ), + + str_terminfo (strSaveCursorPos, "sc" ), + str_terminfo (strRestoreCursorPos, "rc" ), + + str_terminfo (strBell, "bl"), +}; + +#endif + +#ifndef BLASSIC_CONFIG_USE_NCURSES + +char tgetent_buffer [1024]; + +#endif + +void init () +{ + TRACEFUNC (tr, "init"); + + fInit= false; + #ifdef BLASSIC_CONFIG_USE_NCURSES + { + int errret; + setupterm (0, 1, & errret); + } + #else + { + char * strterm= getenv ("TERM"); + if (strterm != NULL && strterm [0] != '\0') + tgetent (tgetent_buffer, strterm); + } + #endif + + for (size_t i= 0; i < util::dim_array (strinfo); ++i) + strinfo [i].str= mytigetstr (strinfo [i].tinfoname); + + initkeytable (); + + if (isatty (STDOUT_FILENO) ) + { + #if 0 + const char * str_keypad_xmit= calltigetstr ("smkx"); + calltputs (str_keypad_xmit); + #else + calltputs (strKeypadXmit); + #endif + } + +} + +inline void checkinit () +{ + if (fInit) + init (); +} + +#else + +inline void checkinit () { } + +#endif + +#endif + +} // namespace + +void cursor::initconsole () +{ + TRACEFUNC (tr, "initconsole"); + + cursorinvisible (); +} + +void cursor::quitconsole () +{ + TRACEFUNC (tr, "quitconsole"); + + cursorvisible (); + + #ifdef BLASSIC_USE_TERMINFO + + if (! fInit) + { + if (isatty (STDOUT_FILENO) ) + { + #if 0 + const char * str_keypad_local= calltigetstr ("rmkx"); + calltputs (str_keypad_local); + #else + calltputs (strKeypadLocal); + #endif + } + + } + + #endif +} + +size_t cursor::getwidth () +{ + const size_t default_value= 80; + size_t width; + + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + width= info.dwSize.X; + else + width= default_value; + + #elif defined BLASSIC_USE_TERMINFO + + STRUCT_WINSIZE win; + if (ioctl (0, IOCTL_WINSIZE, & win) == 0) + width= WINSIZE_COLS (win); + else + { + const char * aux= getenv ("COLUMNS"); + if (aux) + width= atoi (aux); + else + width= default_value; + } + + #else + + width= default_value; + + #endif + + return width; +} + +void cursor::cursorvisible () +{ + TRACEFUNC (tr, "cursorvisible"); + + // checkinit not needed, is done by showcursor + showcursor (); + + #ifndef BLASSIC_USE_WINDOWS + + struct termios ter; + tcgetattr (STDIN_FILENO, & ter); + //ter.c_lflag|= (ECHO | ICANON | PENDIN); + ter.c_lflag|= (ECHO | ICANON); + tcsetattr (STDIN_FILENO, TCSANOW, & ter); + + #endif +} + +void cursor::cursorinvisible () +{ + TRACEFUNC (tr, "cursorinvisible"); + + // checkinit not needed, is done by hidecursor + hidecursor (); + + #ifndef BLASSIC_USE_WINDOWS + + struct termios ter; + tcgetattr (STDIN_FILENO, & ter); + ter.c_lflag&= ~ (ECHO | ICANON); + ter.c_cc [VMIN]= 1; + tcsetattr (STDIN_FILENO, TCSANOW, & ter); + + #endif +} + +void cursor::showcursor () +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO info; + GetConsoleCursorInfo (h, & info); + info.bVisible= TRUE; + SetConsoleCursorInfo (h, & info); + + #elif defined BLASSIC_USE_TERMINFO + + checkinit (); + + if (isatty (STDOUT_FILENO) ) + calltputs (strCursorNormal ); + + #endif +} + +void cursor::hidecursor () +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO info; + GetConsoleCursorInfo (h, & info); + info.bVisible= FALSE; + SetConsoleCursorInfo (h, & info); + + #elif defined BLASSIC_USE_TERMINFO + + checkinit (); + + if (isatty (STDOUT_FILENO) ) + calltputs (strCursorInvisible); + + #endif +} + +#ifdef BLASSIC_USE_WINDOWS + +const WORD init_attributes= + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; +WORD attributes= init_attributes; + +#endif + +void cursor::cls () +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + if (h != INVALID_HANDLE_VALUE) + { + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + { + DWORD l= info.dwSize.X * info.dwSize.Y; + COORD coord= {0, 0}; + DWORD notused; + FillConsoleOutputAttribute (h, + attributes, + l, coord, & notused); + FillConsoleOutputCharacter (h, + ' ', l, coord, & notused); + SetConsoleCursorPosition (h, coord); + } + } + + #elif defined BLASSIC_USE_TERMINFO + + checkinit (); + + calltputs (strCls); + + #endif +} + +void cursor::gotoxy (int x, int y) +{ + #ifdef BLASSIC_USE_WINDOWS + + COORD coord= { SHORT (x), SHORT (y) }; + SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coord); + + #elif defined BLASSIC_USE_TERMINFO + + checkinit (); + + if (strCup) + calltputs (tgoto (const_cast <char *> (strCup), x, y) ); + + #else + + touch (x, y); + + #endif +} + +int cursor::getcursorx () +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) == 0) + return 0; + return info.dwCursorPosition.X; + + #else + + return 0; + + #endif +} + +void cursor::movecharforward () +{ + #ifdef BLASSIC_USE_WINDOWS + + movecharforward (1); + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strMoveForward); + + #endif +} + +void cursor::movecharback () +{ + #ifdef BLASSIC_USE_WINDOWS + + movecharback (1); + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strMoveBack); + + #endif +} + +void cursor::movecharup () +{ + #ifdef BLASSIC_USE_WINDOWS + + movecharup (1); + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strMoveUp); + + #endif +} + +void cursor::movechardown () +{ + #ifdef BLASSIC_USE_WINDOWS + + movechardown (1); + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strMoveDown); + + #endif +} + +namespace { + +#ifdef BLASSIC_USE_TERMINFO + +inline void auxmovechar (const char * strN, const char * str, size_t n) +{ + if (n != 0) + { + if (strN) + //calltputs (tparm ( (char *) strN, n) ); + calltparm (strN, n); + else + if (str) + for (size_t i= 0; i < n; ++i) + calltputs (str); + } +} + +#endif + +} // namespace + +void cursor::movecharforward (size_t n) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + { + info.dwCursorPosition.X+= SHORT (n); + SetConsoleCursorPosition (h, info.dwCursorPosition); + } + + #elif defined BLASSIC_USE_TERMINFO + + auxmovechar (strMoveForwardN, strMoveForward, n); + + #else + + touch (n); + + #endif +} + +void cursor::movecharback (size_t n) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + { + info.dwCursorPosition.X-= SHORT (n); + SetConsoleCursorPosition (h, info.dwCursorPosition); + } + + #elif defined BLASSIC_USE_TERMINFO + + auxmovechar (strMoveBackN, strMoveBack, n); + + #else + + touch (n); + + #endif +} + +void cursor::movecharup (size_t n) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + { + info.dwCursorPosition.Y-= SHORT (n); + SetConsoleCursorPosition (h, info.dwCursorPosition); + } + + #elif defined BLASSIC_USE_TERMINFO + + auxmovechar (strMoveUpN, strMoveUp, n); + + #else + + touch (n); + + #endif +} + +void cursor::movechardown (size_t n) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo (h, & info) ) + { + info.dwCursorPosition.Y+= SHORT (n); + SetConsoleCursorPosition (h, info.dwCursorPosition); + } + + #elif defined BLASSIC_USE_TERMINFO + + auxmovechar (strMoveDownN, strMoveDown, n); + + #else + + touch (n); + + #endif +} + +void cursor::savecursorpos () +{ + #ifdef BLASSIC_USE_WINDOWS + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strSaveCursorPos); + + #endif +} + +void cursor::restorecursorpos () +{ + #ifdef BLASSIC_USE_WINDOWS + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strRestoreCursorPos); + + #endif +} + + +#ifndef BLASSIC_USE_WINDOWS + +namespace { + +static const int newcolor []= + { 0, 4, 2, 6, 1, 5, 3, 7}; + +inline int mapcolor (int n) +{ + // Intensity bit unchanged + return newcolor [n & 7] | (n & 8); +} + +} // namespace + +#endif + +void cursor::textcolor (int color) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + attributes= (attributes & WORD (0xF0) ) | WORD (color & 0x0F); + SetConsoleTextAttribute (h, attributes); + + #elif defined BLASSIC_USE_TERMINFO + + color= mapcolor (color & 0xF); + bool intensity= color > 7; + if (intensity) + { + color&= 7; + calltputs (strEnterBold); + } + else + { + if (strExitBold) + { + calltputs (strExitBold); + // sgr0 reset the background, then we need to set it. + textbackground (background); + } + } + //if (strForeground) + // calltputs (tparm ( (char *) strForeground, color) ); + calltparm (strForeground, color); + + #else + + touch (color); + + #endif +} + +void cursor::textbackground (int color) +{ + #ifdef BLASSIC_USE_WINDOWS + + HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE); + attributes= (attributes & WORD (0xF) ) | WORD ( (color & 0xF) << 4); + SetConsoleTextAttribute (h, attributes); + + #elif defined BLASSIC_USE_TERMINFO + + background= color; + color= mapcolor (color & 0xF); + //if (strBackground) + // calltputs (tparm ( (char *) strBackground, color) ); + calltparm (strBackground, color); + + #else + + touch (color); + + #endif +} + +namespace { + +enum ReadType { ReadWait, ReadNoWait }; + +#ifdef BLASSIC_USE_WINDOWS + +std::string string_from_key_event (const KEY_EVENT_RECORD & kr) +{ + + char c= kr.uChar.AsciiChar; + if (c != '\0') + return std::string (1, c); + WORD k= kr.wVirtualKeyCode; + std::string str= string_from_key (k); + if (! str.empty () ) + return str; + + if (k != VK_SHIFT && + k != VK_CONTROL && + k != VK_MENU && + k != VK_CAPITAL && + k != VK_NUMLOCK && + k != VK_SCROLL) + { + std::string str (1, '\0'); + str+= char (kr.wVirtualScanCode); + return str; + } + return std::string (); +} + +std::string string_from_input (const INPUT_RECORD & input) +{ + std::string str; + if (input.EventType == KEY_EVENT && input.Event.KeyEvent.bKeyDown) + { + str= string_from_key_event (input.Event.KeyEvent); + } + return str; +} + +std::string readkey (ReadType type) +{ + std::string str; + + HANDLE h= GetStdHandle (STD_INPUT_HANDLE); + if (h == INVALID_HANDLE_VALUE) + { + showlasterror (); + throw ErrFileRead; + } + + DWORD mode, orgmode; + GetConsoleMode (h, & mode); + orgmode= mode; + //mode&= ~ (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); + mode= 0; + SetConsoleMode (h, mode); + DWORD n= 0; + INPUT_RECORD input; + if (type == ReadNoWait) + { + if (PeekConsoleInput (h, & input, 1, & n) == 0) + { + showlasterror (); + throw ErrFileRead; + } + } + else + n= 1; + if (n) + { + do + { + if (ReadConsoleInput (h, & input, 1, & n) == 0) + { + showlasterror (); + throw ErrFileRead; + } + str= string_from_input (input); + } while (type == ReadWait && str.empty () ); + } + SetConsoleMode (h, orgmode); + + return str; +} + +#else + +#if defined BLASSIC_USE_TERMINFO + +class MapSpecial { +public: + enum Result { NoMapped, Found, MoreNeeded }; + void addkey (const std::string & str, std::string::size_type pos, + const std::string & keyname) + { + //TRACEFUNC (tr, "MapSpecial::addkey"); + + ASSERT (pos < str.size () ); + char c= str [pos]; + if (pos == str.size () - 1) + kname [c]= keyname; + else + { + //if (kmap.find (c) == kmap.end () ) + // kmap [c]= MapSpecial (); + kmap [c].addkey (str, pos + 1, keyname); + } + } + Result findkey (const std::string & str, std::string::size_type pos, + std::string & keyname, std::string::size_type & consumed) + { + if (pos >= str.size () ) + return MoreNeeded; + char c= str [pos]; + //cout << "Buscando: " << c << endl; + { + kname_t::iterator it= kname.find (c); + if (it != kname.end () ) + { + keyname= it->second; + consumed= pos; + return Found; + } + } + std::map <char, MapSpecial>::iterator it= kmap.find (c); + if (it != kmap.end () ) + return it->second.findkey + (str, pos + 1, keyname, consumed); + else + return NoMapped; + } +private: + typedef std::map <char, std::string> kname_t; + kname_t kname; + std::map <char, MapSpecial> kmap; +}; + +struct KeyDescription { + const char * tiId; + //const char * blName; + const std::string & blName; + KeyDescription (const char * tiId, const std::string & blName) : + tiId (tiId), + blName (blName) + { } +}; + +const std::string + strMULT ("*"), + strMINUS ("-"), + strPLUS ("+"), + strDIV ("/"); + +#ifdef BLASSIC_CONFIG_USE_NCURSES + +const KeyDescription keyname [] = { + KeyDescription ("kpp", strPAGEUP), // previous-page key + KeyDescription ("knp", strPAGEDOWN), // next-page key + KeyDescription ("kend", strEND), // end key + KeyDescription ("kslt", strEND), // select key + KeyDescription ("kc1", strEND), // lower left of keypad + KeyDescription ("khome", strHOME), // home key + KeyDescription ("kfnd", strHOME), // find key + KeyDescription ("ka1", strHOME), // upper left of keypad + KeyDescription ("kcub1", strLEFT), // left-arrow key + KeyDescription ("kcuu1", strUP), // up-arrow key + KeyDescription ("kcuf1", strRIGHT), // right-arrow key + KeyDescription ("kcud1", strDOWN), // down-arrow key + KeyDescription ("kich1", strINSERT), // insert-character key + KeyDescription ("kdch1", strDELETE), // delete-character key + KeyDescription ("kent", strENTER), // enter/send key + KeyDescription ("kf1", strF1), // F1 function key + KeyDescription ("kf2", strF2), // F2 function key + KeyDescription ("kf3", strF3), // F3 function key + KeyDescription ("kf4", strF4), // F4 function key + KeyDescription ("kf5", strF5), // F5 function key + KeyDescription ("kf6", strF6), // F6 function key + KeyDescription ("kf7", strF7), // F7 function key + KeyDescription ("kf8", strF8), // F8 function key + KeyDescription ("kf9", strF9), // F9 function key + KeyDescription ("kf10", strF10), // F10 function key + KeyDescription ("kf11", strF11), // F11 function key + KeyDescription ("kf12", strF12), // F12 function key + KeyDescription ("kf54", strDIV), // F54 function key, / in xterm + KeyDescription ("kf55", strMULT), // F55 function key, * in xterm + KeyDescription ("kf56", strMINUS), // F56 function key, - in xterm + KeyDescription ("kf57", strPLUS), // f57 function key, + in xterm +}; + +#else + +const KeyDescription keyname [] = { + KeyDescription ("kP", strPAGEUP), // previous-page key + KeyDescription ("kN", strPAGEDOWN), // next-page key + KeyDescription ("@7", strEND), // end key + KeyDescription ("*6", strEND), // select key + KeyDescription ("K4", strEND), // lower left of keypad + KeyDescription ("kh", strHOME), // home key + KeyDescription ("@0", strHOME), // find key + KeyDescription ("K1", strHOME), // upper left of keypad + KeyDescription ("kl", strLEFT), // left-arrow key + KeyDescription ("ku", strUP), // up-arrow key + KeyDescription ("kr", strRIGHT), // right-arrow key + KeyDescription ("kd", strDOWN), // down-arrow key + KeyDescription ("kI", strINSERT), // insert-character key + KeyDescription ("kD", strDELETE), // delete-character key + KeyDescription ("@8", strENTER), // enter/send key + KeyDescription ("k1", strF1), // F1 function key + KeyDescription ("k2", strF2), // F2 function key + KeyDescription ("k3", strF3), // F3 function key + KeyDescription ("k4", strF4), // F4 function key + KeyDescription ("k5", strF5), // F5 function key + KeyDescription ("k6", strF6), // F6 function key + KeyDescription ("k7", strF7), // F7 function key + KeyDescription ("k8", strF8), // F8 function key + KeyDescription ("k9", strF9), // F9 function key + KeyDescription ("k;", strF10), // F10 function key + KeyDescription ("F1", strF11), // F11 function key + KeyDescription ("F2", strF12), // F12 function key + KeyDescription ("Fi", strDIV), // F54 function key, / in xterm + KeyDescription ("Fj", strMULT), // F55 function key, * in xterm + KeyDescription ("Fk", strMINUS), // F56 function key, - in xterm + KeyDescription ("Fl", strPLUS), // f57 function key, + in xterm +}; + +#endif + +#ifndef NDEBUG + +bool checktable () +{ + const size_t nkeys= util::dim_array (keyname); + + for (size_t i= 0; i < nkeys - 1; ++i) + for (size_t j= i + 1; j < nkeys; ++j) + if (strcmp (keyname [i].tiId, keyname [j].tiId) == 0) + { + std::cerr << "Code repeated in keyname: " << + keyname [i].tiId << std::endl; + throw 1; + } + return true; +} + +bool tablechecked= checktable (); + +#endif + +MapSpecial ms; + +void initkeytable () +{ + TRACEFUNC (tr, "initkeytable"); + + const size_t nkeys= util::dim_array (keyname); + + for (size_t i= 0; i < nkeys; ++i) + { + const KeyDescription & keydesc= keyname [i]; + const char * const strkey= keydesc.tiId; + const char * str= calltigetstr (strkey); + if (str != NULL) + { + #if 0 + cerr << keydesc.blName << "="; + for (size_t i= 0, l= strlen (str); i < l; ++i) + { + char c= str [i]; + if (c >= 32) cerr << c; + else cerr << "\\(" << hex << int (c) << ')'; + } + cerr << endl; + #endif + TRMESSAGE (tr, std::string ("Adding ") + keydesc.blName); + ms.addkey (str, 0, keydesc.blName); + } + } + +} + +#endif // BLASSIC_USE_TERMINFO + +class PollInput { +public: + PollInput () + { + pfd.fd= STDIN_FILENO; + pfd.events= POLLIN; + } + int poll () + { + int r= ::poll (& pfd, 1, 100); + if (r == 1 && pfd.revents != POLLIN) + throw ErrFileRead; + return r; + } +private: + struct pollfd pfd; +}; + +void wait_event () +{ + PollInput pi; + int r; + do { + blassic::idle (); + } while ( (r= pi.poll () ) == 0); + if (r < 0) + { + std::cerr << "Error in poll: " << strerror (errno) << + std::endl; + } +} + +void do_poll () +{ + PollInput ().poll (); +} + +std::string readkey (ReadType type) +{ + checkinit (); + + static std::string charpending; + std::string str; + bool reset_blocking_mode= false; + int l; + //char c; + const int lbuf= 32; + char buffer [lbuf + 1]; + + if (! charpending.empty () ) + goto check_it; + + #if 0 + + if (type == ReadWait) + { + //fcntl (STDIN_FILENO, F_SETFL, 0); + wait_event (); + } + else + { + fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK); + reset_blocking_mode= true; + } + + //read_another: + + l= read (STDIN_FILENO, & c, 1); + if (l == 1) + str+= c; + + #else + + fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK); + reset_blocking_mode= true; + //l= read (STDIN_FILENO, & c, 1); + l= read (STDIN_FILENO, buffer, lbuf); + //if (l != 1 && type == ReadWait) + if (l < 1 && type == ReadWait) + { + do { + //wait_event (); + //l= read (STDIN_FILENO, & c, 1); + do_poll (); + l= read (STDIN_FILENO, buffer, lbuf); + //} while (l != 1); + } while (l < 1); + } + //if (l == 1) + // str+= c; + if (l >= 1) + { + buffer [l]= '\0'; + str+= buffer; + } + + #endif + + #ifdef BLASSIC_USE_TERMINFO + read_another: + #endif + + //std::cerr << "Adding: >" << str << '<' << std::endl; + charpending+= str; + str.erase (); + + check_it: + + std::string keyname; + //std::string::size_type pos; + if (! charpending.empty () ) + { + #ifdef BLASSIC_USE_TERMINFO + std::string::size_type pos; + MapSpecial::Result r= + ms.findkey (charpending, 0, keyname, pos); + switch (r) + { + case MapSpecial::NoMapped: + str= charpending [0]; + charpending.erase (0, 1); + break; + case MapSpecial::Found: + str= keyname; + charpending.erase (0, pos + 1); + break; + case MapSpecial::MoreNeeded: + fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK); + reset_blocking_mode= true; + do_poll (); + //l= read (STDIN_FILENO, & c, 1); + //if (l == 1) + //{ + // str= c; + // goto read_another; + //} + l= read (STDIN_FILENO, buffer, lbuf); + if (l >= 1) + { + buffer [l]= '\0'; + str= buffer; + goto read_another; + } + str= charpending [0]; + charpending.erase (0, 1); + break; + } + #else + str= charpending [0]; + charpending.erase (0, 1); + #endif + } + + //if (type == ReadWait) + // cursorinvisible (); + + if (reset_blocking_mode) + fcntl (STDIN_FILENO, F_SETFL, 0); + + return str; +} + +#endif // ! BLASSIC_USE_WINDOWS + +// A provisional solution to pollin + +std::queue <std::string> keypending; + +} // namespace + +std::string cursor::inkey () +{ + if (! keypending.empty () ) + { + std::string r= keypending.front (); + keypending.pop (); + return r; + } + else + return readkey (ReadNoWait); +} + +std::string cursor::getkey () +{ + if (! keypending.empty () ) + { + std::string r= keypending.front (); + keypending.pop (); + return r; + } + return readkey (ReadWait); +} + +bool cursor::pollin () +{ + if (! keypending.empty () ) + return true; + else + { + std::string key= readkey (ReadNoWait); + if (key.empty () ) + return false; + else + { + keypending.push (key); + return true; + } + } +} + +void cursor::clean_input () +{ + TRACEFUNC (tr, "clean_input"); + + #ifdef BLASSIC_USE_WINDOWS + + Sleep (100); + HANDLE h= GetStdHandle (STD_INPUT_HANDLE); + INPUT_RECORD input; + DWORD n= 0; + PeekConsoleInput (h, & input, 1, & n); + if (n && input.EventType == KEY_EVENT && + ! input.Event.KeyEvent.bKeyDown) + ReadConsoleInput (h, & input, 1, & n); + + #else + + fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK); + int l; + const int lbuf= 32; + char buffer [lbuf + 1]; + do + { + l= read (STDIN_FILENO, buffer, lbuf); + } while (l > 0); + fcntl (STDIN_FILENO, F_SETFL, 0); + + #endif +} + +void cursor::ring () +{ + #ifdef BLASSIC_USE_WINDOWS + + MessageBeep (MB_ICONEXCLAMATION); + + #elif defined BLASSIC_USE_TERMINFO + + calltputs (strBell); + + #else + + // Last resource + char c= '\a'; + write (STDOUT_FILENO, & c, 1); + + #endif +} + +//************************************************ +// set_title +//************************************************ + +#ifdef BLASSIC_USE_TERMINFO + +// Escape sequences from the "How to change the title of an xterm", +// by Ric Lister, http://www.tldp.org/HOWTO/mini/Xterm-Title.html + +namespace +{ + +void write_it (std::ostringstream & oss) +{ + const std::string & str (oss.str () ); + write (STDOUT_FILENO, str.c_str (), str.size () ); +} + +void set_title_xterm (const std::string & title) +{ + std::ostringstream oss; + oss << "\x1B]0;" << title << "\x07"; + write_it (oss); +} + +void set_title_iris_ansi (const std::string & title) +{ + std::ostringstream oss; + oss << "\x1BP1.y" << title << "\x1B\\"; // Set window title + oss << "\x1BP3.y" << title << "\x1B\\"; // Set icon title + write_it (oss); +} + +void set_title_sun_cmd (const std::string & title) +{ + std::ostringstream oss; + oss << "\x1B]l;" << title << "\x1B\\"; // Set window title + oss << "\x1B]L;" << title << "\x1B\\"; // Set icon title + write_it (oss); +} + +void set_title_hpterm (const std::string & title) +{ + std::ostringstream oss; + const std::string::size_type l= title.size (); + oss << "\x1B&f0k" << l << 'D' << title; // Set window title + oss << "\x1B&f-1k" << l << 'D' << title; // Set icon title + write_it (oss); +} + +typedef void (* set_title_t) (const std::string &); + +struct Cstring_less { + bool operator () (const char * p, const char * q) + { return strcmp (p, q) < 0; } +}; + +typedef std::map <const char *, set_title_t, Cstring_less> maptitle_t; +maptitle_t maptitle; + +bool initmaptitle () +{ + maptitle ["xterm"]= set_title_xterm; + maptitle ["aixterm"]= set_title_xterm; + maptitle ["dtterm"]= set_title_xterm; + maptitle ["iris-ansi"]= set_title_iris_ansi; + maptitle ["sun-cmd"]= set_title_sun_cmd; + maptitle ["hpterm"]= set_title_hpterm; + return true; +} + +bool maptitle_inited= initmaptitle (); + +void set_title_terminfo (const std::string & title) +{ + TRACEFUNC (tr, "set_title_terminfo"); + + if (! isatty (STDOUT_FILENO) ) + return; + + if (const char * term= getenv ("TERM") ) + { + maptitle_t::iterator it= maptitle.find (term); + if (it != maptitle.end () ) + (* it->second) (title); + else + { + TRMESSAGE (tr, "TERM not found"); + } + } +} + +} // namespace + +#endif + +void cursor::set_title (const std::string & title) +{ + TRACEFUNC (tr, "set_title"); + + #ifdef BLASSIC_USE_WINDOWS + + SetConsoleTitle (title.c_str () ); + + #elif defined BLASSIC_USE_TERMINFO + + set_title_terminfo (title); + + #else + + touch (title); + + #endif +} + +// Fin de cursor.cpp |