unix_curses.h

Go to the documentation of this file.
00001 //
00002 // Copyright 2002, Lowell Boggs Jr.
00003 //
00004 // This file or directory, containing source code for a computer program,
00005 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00006 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00007 // source file without charge or obligation so long as you agree to
00008 // the following:
00009 //
00010 //  1.  You must indemnify Lowell Boggs against any and all financial
00011 //      obligations caused by its use, misuse, function, or malfunction.
00012 //      Further, you acknowledge that there is no warranty of any kind,
00013 //      whatsoever.
00014 //
00015 //  2.  You agree not to attempt to patent any portion of this original
00016 //      work -- though you may attempt to patent your own extensions to
00017 //      it if you so choose.
00018 //
00019 //  3.  You keep this copyright notice with the file and all copies
00020 //      of the file and do not change it anyway except language translation.
00021 //
00022 // You are responsible for enforcing your own compliance with these
00023 // conditions and may not use this source file if you cannot agree to the
00024 // above terms and conditions.
00025 
00057 
00058 #include <cxxtls/cursorwindow.h>
00059 #include <cxxtls/sequence_map.h>
00060 #include <string>
00061 #include <stdlib.h>
00062 #include <unistd.h>
00063 #include <signal.h>
00064 #include <algorithm>
00065 #include <cxxtls/file.h>
00066 #include <cxxtls/user.h>
00067 #include <cxxtls/machine.h>
00068 #include <iostream>
00069 #include <fstream>
00070 #include <portable_io.h>
00071 
00072 #include <cxxtls/cursesinterface.h>
00073 
00074 
00075 extern "C"
00076 {
00077 #ifndef _XOPEN_SOURCE_EXTENDED
00078 #define _XOPEN_SOURCE_EXTENDED
00079 #endif
00080 
00081 #define NOMACROS
00082 #include <curses.h>
00083 
00084 #undef clear
00085 int clear();
00086 
00087 }
00088 
00089 #include <term.h>
00090 #include <termios.h>
00091 
00092 namespace cxxtls
00093 {
00094 
00095 
00096 namespace CursesInterface
00097 {
00098   bool screen_resize_occurred=0;
00099 
00100 
00101 #ifdef _MSC_VER
00102   mouse_info read_mouse_info() { return mouse_location(0,0,0); } // not yet implemented
00103 #endif
00104 
00105   long line_chars[lcCOUNT];
00106 
00107   char* _map_kf1  ;  // global variables holding function key sequences
00108   char* _map_kf2  ;  // obtained from the term.h header file after the
00109   char* _map_kf3  ;  // terminal is opened.
00110   char* _map_kf4  ;
00111   char* _map_kf5  ;
00112   char* _map_kf6  ;
00113   char* _map_kf7  ;
00114   char* _map_kf8  ;
00115   char* _map_kf9  ;
00116   char* _map_kf10 ;
00117   char* _map_kf11 ;
00118   char* _map_kf12 ;
00119   char* _map_khom ;
00120   char* _map_kend ;
00121   char* _map_kic  ;
00122   char* _map_kdc  ;
00123   char* _map_kpr  ;
00124   char* _map_knx  ;
00125   char* _map_kup  ;
00126   char* _map_kdn  ;
00127   char* _map_klf  ;
00128   char* _map_krt  ;
00129   char* _map_kbtab;
00130 
00131   void map_init_key_strings()
00132   {
00133      _map_kf1  = key_f1;
00134      _map_kf2  = key_f2;
00135      _map_kf3  = key_f3;
00136      _map_kf4  = key_f4;
00137      _map_kf5  = key_f5;
00138      _map_kf6  = key_f6;
00139      _map_kf7  = key_f7;
00140      _map_kf8  = key_f8;
00141      _map_kf9  = key_f9;
00142      _map_kf10 = key_f10;
00143      _map_kf11 = key_f11;
00144      _map_kf12 = key_f12;
00145      _map_khom = key_home;
00146      _map_kend = key_end;
00147      _map_kic  = key_ic;
00148      _map_kdc  = key_dc;
00149      _map_kpr  = key_ppage;
00150      _map_knx  = key_npage;
00151      _map_kup  = key_up;
00152      _map_kdn  = key_down;
00153      _map_klf  = key_left;
00154      _map_krt  = key_right;
00155      _map_kbtab= key_btab;
00156 
00157 
00158   }
00159 
00160 typedef Sequence_Map<char,int> SEQMAP;
00161 typedef SEQMAP::search         SEARCH;
00162 typedef SEQMAP::sequence       SEQUENCE;
00163 
00164 SEQMAP key_sequences;
00165 
00166 void insert_key_sequence(char const *s, int code)
00167 {
00168    if(s == 0)
00169      return;
00170 
00171    SEQUENCE seq(key_sequences, code);
00172 
00173    while(*s)
00174    {
00175       seq += *s++;
00176    }
00177 
00178    seq.complete();
00179 
00180 }
00181 
00182 void create_key_sequences_map();
00183 
00184 
00185 sigset_t winch_blocker;  // holds 'SIGWINCH' flag (window change signal)
00186 
00187 void make_xterm_terminfo_file(FileName const &dir);
00188 
00189 
00190 #ifdef __linux
00191 static bool quit_occurred;
00192 static bool susp_occurred;
00193 static bool int_occurred;
00194 
00195   extern "C"
00196   {
00197     static void quit_handler(int)
00198     {
00199       quit_occurred=1;
00200       signal(SIGQUIT, quit_handler); // re-enable signal
00201     }
00202   }
00203 
00204   extern "C"
00205   {
00206     static void susp_handler(int)
00207     {
00208       susp_occurred=1;
00209       signal(SIGTSTP, susp_handler); // re-enable signal
00210     }
00211   }
00212 
00213 
00214   extern "C"
00215   {
00216     static void int_handler(int)
00217     {
00218       int_occurred=1;
00219       signal(SIGINT, int_handler); // re-enable signal
00220     }
00221   }
00222 
00223 
00224 
00225 
00226 #endif
00227 
00228 
00229 void openCursesTerminal()
00230 {
00231 #ifdef __linux
00232   quit_occurred = false;
00233   susp_occurred = false;
00234   int_occurred  = false;
00235 #endif
00236 
00237   if(getenv("WAIT_FOR_DEBUGGER"))
00238   {
00239      printf("waiting for debugger to attach and single step this program\n");
00240 
00241      int stop=1;
00242 
00243      while(stop)
00244      {
00245         sleep(1);
00246      }
00247 
00248   }
00249 
00250 static bool first_time=true;
00251 if(first_time)
00252 { // begin environment settings
00253 
00254   first_time =false;
00255 
00256 
00257   char const *termname = getenv("TERM");
00258 
00259   if(   termname == 0 
00260      || (   termname[0] != 'x'
00261          && termname != std::string("cygwin")
00262         )
00263     )
00264   {
00265     std::cerr << "Error, right now I only support TERM=xterm" << std::endl;
00266     exit(1);
00267   }
00268 
00269   UserInfo me = UserInfo::get();
00270 
00271   if(me.name_ == "")
00272   {
00273     std::cerr << "Error, couldn't get user id info -- system error" << std::endl;
00274     exit(1);
00275   }
00276 
00277   FileName tooldir = me.home_dir_ + "/.tools_home";
00278 
00279   if( !tooldir.is_dir() )
00280   {
00281     // need to create the tools TERMINFO files
00282 
00283     if(tooldir.mkdir())
00284     {
00285       std::cerr << "Error, couldn't create " << tooldir << std::endl;
00286       exit(1);
00287     }
00288 
00289   }
00290 
00291   MachineInfo host = MachineInfo::get();
00292 
00293   if(host.hostname_ == "")
00294   {
00295     std::cerr << "Error, couldn't get hostname" << std::endl;
00296     exit(1);
00297   }
00298 
00299   FileName hostdir = tooldir + "/" + host.hostname_;
00300 
00301   if(!hostdir.is_dir())
00302   {
00303     // need to create host specific terminfo
00304 
00305     if(hostdir.mkdir())
00306     {
00307       std::cerr << "Error, couldn't create " << hostdir << std::endl;
00308       exit(1);
00309     }
00310 
00311   }
00312 
00313   make_xterm_terminfo_file(hostdir);
00314 
00315   FileName terminfodir  = hostdir;
00316            terminfodir += "/terminfo";
00317 
00318   if(!terminfodir.is_dir())
00319   {
00320     // need to create host specific terminfo
00321 
00322     if(terminfodir.mkdir())
00323     {
00324       std::cerr << "Error, couldn't create " << terminfodir << std::endl;
00325       exit(1);
00326     }
00327 
00328   }
00329 
00330   FileName xterm_info_file  = terminfodir;
00331            xterm_info_file += "/x/xterm";
00332 
00333   std::string command("TERMINFO=");
00334 
00335               command += terminfodir;
00336               command += " ";
00337               command += "/usr/bin/tic ";
00338               command += hostdir + "/xterm.info";
00339 
00340   if(!xterm_info_file.exists())
00341   {
00342     int err = system(command.c_str());
00343 
00344     (void)err;
00345   }
00346 
00347   if(!xterm_info_file.exists())
00348   {
00349     //  the xterm.info file did not get created.
00350     //  Normally this is an error but on suse linux, SLES to be precise, the 
00351     //  /usr/bin/tic program has a bug in it that causes it to write on the
00352     //  system directories and ignore the TERMINFO environment variable.
00353     //  SO, the root user on SLES cannot get past this without hand creating the link.
00354     // 
00355 
00356     int uid = getuid();
00357 
00358     if(uid == 0)
00359     {
00360         command="mkdir -p " + terminfodir + "/x" + "\n";
00361 
00362         int rc;
00363 
00364         rc = system(command.c_str());
00365 
00366         command="ln -s /usr/share/terminfo/x/xterm " + xterm_info_file + "\n"; 
00367         
00368         rc = system(command.c_str());
00369 
00370         rc=rc;
00371         
00372     }
00373 
00374       if(!xterm_info_file.exists())
00375       {
00376         std::cerr << "Error, command '" << command << "', did not create" << std::endl
00377                   << "file " << xterm_info_file << std::endl;
00378       
00379         exit(1);
00380       }
00381   }
00382 
00383   static char * envstring=0;
00384 
00385   std::string tmp1("TERMINFO=");
00386               tmp1 += terminfodir;
00387         
00388   char const *tmp2 = tmp1.c_str();
00389 
00390   int l = strlen(tmp2);
00391 
00392   envstring = new char[l+1];
00393 
00394   strcpy(envstring, tmp2);
00395 
00396   putenv(envstring);
00397 
00398 } // end environment settings
00399 
00400 
00401 
00402   initscr();
00403 
00404   raw();
00405   noecho();
00406   meta(stdscr, TRUE);
00407 
00408   halfdelay(10);
00409 
00410   intrflush(stdscr,FALSE);
00411   keypad(stdscr,TRUE);
00412   typeahead(0);  /* tells refresh() to check for pending input() */
00413 
00414 
00415   #ifdef __linux
00416 
00417 
00418     static struct termios override_termios;
00419 
00420     tcgetattr(0, &override_termios);
00421       
00422     cfmakeraw(&override_termios);
00423 
00424     override_termios.c_cc[VQUIT]=0;
00425     override_termios.c_cc[VSUSP]=0;
00426 
00427     override_termios.c_cc[VMIN]=1;
00428     override_termios.c_cc[VTIME]=10;
00429 
00430     tcsetattr(0, TCSANOW, &override_termios);
00431 
00432   #else
00433 
00434     termios io_info;
00435 
00436 
00437     tcgetattr(0, &io_info);
00438 
00439     io_info.c_cc[VMIN]=1;
00440     io_info.c_cc[VTIME]=10;
00441     tcsetattr(0, TCSANOW, &io_info);
00442 
00443 
00444   #endif
00445 
00446 
00447   // block the sigwinch signal
00448 
00449   sigemptyset(&winch_blocker);
00450 
00451   sigaddset(&winch_blocker, SIGWINCH);
00452 
00453   sigprocmask(SIG_BLOCK, &winch_blocker, 0);
00454 
00455 
00456 
00457   siginterrupt(SIGWINCH, true);
00458   siginterrupt(SIGALRM, true);
00459 
00460 #ifdef __linux
00461   siginterrupt(SIGQUIT, true);
00462   siginterrupt(SIGTSTP, true);
00463   siginterrupt(SIGINT,  true);
00464 #endif
00465 
00466   map_init_key_strings();
00467   create_key_sequences_map();
00468 
00469   using namespace CursesInterface;
00470 
00471   line_chars[UL_CORNER] = ACS_ULCORNER;
00472   line_chars[LL_CORNER] = ACS_LLCORNER;
00473   line_chars[UR_CORNER] = ACS_URCORNER;
00474   line_chars[LR_CORNER] = ACS_LRCORNER;
00475   line_chars[HL_MIDDLE] = ACS_HLINE;
00476   line_chars[VL_MIDDLE] = ACS_VLINE;
00477   line_chars[PL_BOX   ] = ACS_PLUS;
00478   line_chars[TE_LEFT  ] = ACS_LTEE;
00479   line_chars[TE_RIGHT ] = ACS_RTEE; 
00480   line_chars[TE_BOTTOM] = ACS_BTEE;
00481   line_chars[TE_TOP   ] = ACS_TTEE;
00482 
00483 }
00484 
00485 void closeCursesTerminal()
00486 {
00487             attrset(0);
00488             clear();
00489             refresh();
00490             endwin();
00491             #ifdef __linux
00492             resetterm();
00493             #endif
00494 
00495     if(screen_resize_occurred)
00496     {
00497        // make sure the screen is empty
00498 
00499        for(int i = 0; i < 100; ++i)
00500        {
00501           std::cout << "\n";
00502        }
00503 
00504     }
00505 
00506 }
00507 
00508 #undef key_up
00509 #undef key_down
00510 #undef key_left
00511 #undef key_right
00512 #undef key_sup
00513 #undef key_sdown
00514 #undef key_sleft
00515 #undef key_sright
00516 #undef key_prior
00517 #undef key_next
00518 #undef key_ic
00519 #undef key_dc
00520 #undef key_home
00521 #undef key_end
00522 #undef key_btab
00523 #undef key_f1
00524 #undef key_f2
00525 #undef key_f3
00526 #undef key_f4
00527 #undef key_f5
00528 #undef key_f6
00529 #undef key_f7
00530 #undef key_f8
00531 #undef key_f9
00532 #undef key_f10
00533 #undef key_f11
00534 #undef key_f12
00535 #undef erase
00536 
00537 int mapCursesKey(int curses_key)  // map to CursorWindow key representation
00538 {
00539   switch(curses_key)
00540   {
00541     case KEY_UP:    return CursorWindow::key_up;
00542     case KEY_DOWN:  return CursorWindow::key_down;
00543     case KEY_LEFT:  return CursorWindow::key_left;
00544     case KEY_RIGHT: return CursorWindow::key_right;
00545     case KEY_SLEFT: return CursorWindow::key_sleft;
00546     case KEY_SRIGHT:return CursorWindow::key_sright;
00547     case KEY_PPAGE: return CursorWindow::key_prior;
00548     case KEY_NPAGE: return CursorWindow::key_next;
00549     case KEY_IC:    return CursorWindow::key_ic;
00550     case KEY_DC:    return CursorWindow::key_dc;
00551     case KEY_HOME:  return CursorWindow::key_home;
00552     case KEY_SHOME: return CursorWindow::key_home;
00553     case KEY_END:   return CursorWindow::key_end;
00554     case KEY_BTAB:  return CursorWindow::key_btab;
00555 
00556 
00557     #ifdef __linux
00558     case 0x7f:      return CursorWindow::key_bs;
00559     case KEY_BACKSPACE: return CursorWindow::key_bs;
00560     #endif
00561                 
00562     case KEY_F(1):  return CursorWindow::key_f1;
00563     case KEY_F(2):  return CursorWindow::key_f2;
00564     case KEY_F(3):  return CursorWindow::key_f3;
00565     case KEY_F(4):  return CursorWindow::key_f4;
00566     case KEY_F(5):  return CursorWindow::key_f5;
00567     case KEY_F(6):  return CursorWindow::key_f6;
00568     case KEY_F(7):  return CursorWindow::key_f7;
00569     case KEY_F(8):  return CursorWindow::key_f8;
00570     case KEY_F(9):  return CursorWindow::key_f9;
00571     case KEY_F(10): return CursorWindow::key_f10;
00572     case KEY_F(11): return CursorWindow::key_f11;
00573     case KEY_F(12): return CursorWindow::key_f12;
00574   }
00575 
00576   return curses_key;
00577 }
00578 
00579 
00580 
00581 void getCursesCursor(int *row, int *col)
00582 {
00583    getyx(stdscr, *row, *col);
00584 }
00585 
00586 void getCursesScreenSize(int *row, int *col)
00587 {
00588    getmaxyx(stdscr, *row, *col);
00589 }
00590 
00591 
00592 // A_STANDOUT      000010000000
00593 // _STANDOUT       A_STANDOUT    /* for compatability with old curses */
00594 // A_UNDERLINE     000020000000
00595 // A_REVERSE       000040000000
00596 // A_BLINK         000100000000
00597 // A_DIM           000200000000
00598 // A_BOLD          000400000000
00599 // A_ALTCHARSET    001000000000
00600 
00601 void setCursesAttributes( int a )
00602 {
00603   // 'a' is assumed to be a CursorWindow attribute
00604 
00605   int att=0;
00606 
00607   switch(a)
00608   {
00609     case   CursorWindow::reversed:
00610       att = A_REVERSE;
00611       break;
00612 
00613     case   CursorWindow::underlined:
00614       att = A_UNDERLINE;
00615       break;
00616 
00617     case   CursorWindow::blinking:
00618       att = A_BLINK;
00619       break;
00620 
00621     case   CursorWindow::bold:
00622       att = A_BOLD;
00623       break;
00624 
00625     case   CursorWindow::reverse_ul:
00626       att = A_REVERSE | A_UNDERLINE;
00627       break;
00628 
00629     case   CursorWindow::reverse_bold:
00630       att = A_REVERSE | A_BOLD;
00631       break;
00632 
00633     case   CursorWindow::rev_ul_bold:
00634       att = A_REVERSE | A_UNDERLINE | A_BOLD;
00635       break;
00636 
00637     case   CursorWindow::bold_ul:
00638       att = A_UNDERLINE | A_BOLD;
00639       break;
00640 
00641 
00642 
00643     default:
00644       break;
00645   }
00646 
00647   (void)attrset(att);
00648 
00649 }
00650 
00651 
00652 void paintCharString(char const *r, int count, int a, int row, int col)
00653 {
00654     setCursesAttributes(a);
00655 
00656     while(count--)
00657         {
00658             int c = *r++;
00659 
00660             if(c < ' ' ||  (c & 0xff) > 0x7f)
00661             {
00662               c = '`';
00663             }
00664 
00665             mvaddch(row, col++, c);
00666         }
00667 }
00668 
00669 void paintCharString(long c, int count, int a, int row, int col)
00670 {
00671     if(c < ' ' ||  (c & 0xff) > 0x7f)
00672     {
00673       c = '`';
00674     }
00675 
00676     setCursesAttributes(a);
00677 
00678     while(count--)
00679         {
00680             mvaddch(row, col++, c);
00681         }
00682 }
00683 
00684 
00685 
00686 void refreshCursesWindow()
00687 {
00688   refresh();
00689 }
00690 
00691 void beepCursesTerminal()
00692 {
00693   beep();
00694 }
00695 
00696 
00697 void moveCursesCursor(int row, int col)
00698 {
00699   move(row,col);
00700 }
00701 
00702 
00703 void make_xterm_terminfo_file(FileName const &dir)
00709 {
00710   FileName filename = dir;
00711            filename += "/xterm.info";
00712 
00713   if(filename.exists())
00714     return;
00715 
00716   std::fstream f(filename.c_str(), std::ios::out);
00717 
00718   if(f.bad())
00719   {
00720     std::cerr << "Error creating file " << filename << std::endl;
00721     exit(1);
00722   }
00723 
00724 #ifdef LINUX
00725   char const *terminfo =
00726 "#       Reconstructed via infocmp from file: /usr/share/terminfo/x/xterm                                  \n"
00727 "xterm|xterm terminal emulator (X Window System),                                                          \n"
00728 "        am, bce, km, mc5i, mir, msgr, xenl,                                                               \n"
00729 "        colors#8, cols#80, it#8, lines#24, pairs#64,                                                      \n"
00730 "        acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,                                        \n"
00731 "        bel=^G, blink=\\E[5m, bold=\\E[1m, cbt=\\E[Z, civis=\\E[?25l,                                     \n"
00732 "        clear=\\E[H\\E[2J, cnorm=\\E[?25h, cr=^M,                                                         \n"
00733 "        csr=\\E[%i%p1%d;%p2%dr, cub=\\E[%p1%dD, cub1=^H,                                                  \n"
00734 "        cud=\\E[%p1%dB, cud1=^J, cuf=\\E[%p1%dC, cuf1=\\E[C,                                              \n"
00735 "        cup=\\E[%i%p1%d;%p2%dH, cuu=\\E[%p1%dA, cuu1=\\E[A,                                               \n"
00736 "        cvvis=\\E[?25h, dch=\\E[%p1%dP, dch1=\\E[P, dl=\\E[%p1%dM,                                        \n"
00737 "        dl1=\\E[M, ech=\\E[%p1%dX, ed=\\E[J, el=\\E[K, el1=\\E[1K,                                        \n"
00738 "        enacs=\\E(B\\E)0, flash=\\E[?5h$<100/>\\E[?5l, home=\\E[H,                                        \n"
00739 "        hpa=\\E[%i%p1%dG, ht=^I, hts=\\EH, ich=\\E[%p1%d@, ich1=\\E[@,                                    \n"
00740 "        il=\\E[%p1%dL, il1=\\E[L, ind=^J, invis=\\E[8m,                                                   \n"
00741 "        is2=\\E[!p\\E[?3;4l\\E[4l\\E>, kBEG=\\EOu, kDC=\\EOn,                                             \n"
00742 "        kEND=\\EOq, kHOM=\\EOw, kIC=\\EOp, kLFT=\\EOt, kNXT=\\EOr,                                        \n"
00743 "        kPRV=\\EOx, kRIT=\\EOv, ka1=\\EOH, ka3=\\E[5~, kb2=\\EOE,                                         \n"
00744 "        kbeg=\\EOE, kbs=\\177, kc1=\\EOF, kc3=\\E[6~, kcub1=\\EOD,                                        \n"
00745 "        kcud1=\\EOB, kcuf1=\\EOC, kcuu1=\\EOA, kdch1=\\E[3~, kend=\\EOF,                                  \n"
00746 "        kent=\\EOM, kf0=\\E[21~, kf1=\\E[11~, kf10=\\E[21~,                                               \n"
00747 "        kf11=\\E[23~, kf12=\\E[24~, kf13=\\E[25~, kf14=\\E[26~,                                           \n"
00748 "        kf15=\\E[28~, kf16=\\E[29~, kf17=\\E[31~, kf18=\\E[32~,                                           \n"
00749 "        kf19=\\E[33~, kf2=\\E[12~, kf20=\\E[34~, kf21=\\E[35~,                                            \n"
00750 "        kf22=\\E[36~, kf3=\\E[13~, kf4=\\E[14~, kf5=\\E[15~, kf54=\\EOo,                                  \n"
00751 "        kf55=\\EOj, kf56=\\EOm, kf57=\\EOk, kf58=\\EOl, kf6=\\E[17~,                                      \n"
00752 "        kf7=\\E[18~, kf8=\\E[19~, kf9=\\E[20~, kfnd=\\E[1~, khome=\\EOH,                                  \n"
00753 "        kich1=\\E[2~, kind=\\EOs, kmous=\\E[M, knp=\\E[6~, kpp=\\E[5~,                                    \n"
00754 "        kri=\\EOy, kslt=\\E[4~, mc0=\\E[i, mc4=\\E[4i, mc5=\\E[5i,                                        \n"
00755 "        op=\\E[39;49m, rc=\\E8, rev=\\E[7m, ri=\\EM, rmacs=^O,                                            \n"
00756 "        rmam=\\E[?7l, rmcup=\\E[?1047l\\E[?1048l, rmir=\\E[4l,                                            \n"
00757 "        rmkx=\\E[?1l\\E>, rmso=\\E[27m, rmul=\\E[24m,                                                     \n"
00758 "        rs1=\\Ec\\E[?67;9l, rs2=\\E[!p\\E[?3;4l\\E[4l\\E>, sc=\\E7,                                       \n"
00759 "        setab=\\E[4%p1%dm, setaf=\\E[3%p1%dm,                                                             \n"
00760 "        setb=\\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,                     \n"
00761 "        setf=\\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,                     \n"
00762 "        sgr=\\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\\016%e\\017%;, \n"
00763 "        sgr0=\\E[m\\017, smacs=^N, smam=\\E[?7h,                                                          \n"
00764 "        smcup=\\E[?1048h\\E[?1047h, smir=\\E[4h, smkx=\\E[?1h\\E=,                                        \n"
00765 "        smso=\\E[7m, smul=\\E[4m, tbc=\\E[3g, u6=\\E[%i%d;%dR,                                            \n"
00766 "        u7=\\E[6n, u8=\\E[?1;2c, u9=\\E[c, vpa=\\E[%i%p1%dd,                                              \n"
00767 ;
00768 
00769 #else
00770   char const *terminfo =
00771 "#       Reconstructed via infocmp from file: /usr/share/lib/terminfo/x/xterm             \n"
00772 "xterm|vs100|lowells extended xterm terminal emulator,                                    \n"
00773 "        am, km, mir, msgr, xenl,                                                         \n"
00774 "        cols#80, it#8, lines#65,                                                         \n"
00775 "        acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,                         \n"
00776 "        bel=^G, blink=\\E[5m, bold=\\E[1m, clear=\\E[H\\E[2J,                            \n"
00777 "        cr=\\r, csr=\\E[%i%p1%d;%p2%dr, cub=\\E[%p1%dD, cub1=\\b,                        \n"
00778 "        cud=\\E[%p1%dB, cud1=\\n, cuf=\\E[%p1%dC, cuf1=\\E[C,                            \n"
00779 "        cup=\\E[%i%p1%d;%p2%dH, cuu=\\E[%p1%dA, cuu1=\\E[A,                              \n"
00780 "        dch=\\E[%p1%dP, dch1=\\E[P, dl=\\E[%p1%dM, dl1=\\E[M,                            \n"
00781 "        ed=\\E[J, el=\\E[K, el1=\\E[1K$<3>, enacs=\\E(B\\E)0,                            \n"
00782 "        home=\\E[H, ht=\\t, hts=\\EH, ich=\\E[%p1%d@, ich1=\\E[@,                        \n"
00783 "        il=\\E[%p1%dL, il1=\\E[L, ind=\\n, ka1=\\EOq, ka3=\\EOs,                         \n"
00784 "        kb2=\\EOr, kbs=\\b, kc1=\\EOp, kc3=\\EOn, kcub1=\\EOD,                           \n"
00785 "        kcud1=\\EOB, kcuf1=\\EOC, kcuu1=\\EOA, kent=\\EOM,                               \n"
00786 "        kf1=\\E[11~,                                                                     \n"
00787 "        kf10=\\E[21~,                                                                    \n"
00788 "        kf2=\\E[12~,                                                                     \n"
00789 "        kf3=\\E[13~,                                                                     \n"
00790 "        kf4=\\E[14~,                                                                     \n"
00791 "        kf5=\\E[15~,                                                                     \n"
00792 "        kf6=\\E[17~,                                                                     \n"
00793 "        kf7=\\E[18~,                                                                     \n"
00794 "        kf8=\\E[19~,                                                                     \n"
00795 "        kf9=\\E[20~,                                                                     \n"
00796 "        rc=\\E8,                                                                         \n"
00797 "        rev=\\E[7m,                                                                      \n"
00798 "        khome=\\E[1~,                                                                    \n"
00799 "        kend=\\E[4~,                                                                     \n"
00800 "        kll=\\E[E;,                                                                      \n"
00801 "        kpp=\\E[5~,                                                                      \n"
00802 "        knp=\\E[6~,                                                                      \n"
00803 "        kich1=\\E[2~,                                                                    \n"
00804 "        kf11=\\E[23~,                                                                    \n"
00805 "        kf12=\\E[24~,                                                                    \n"
00806 "        kcbt=\\E[TAB;,                                                                   \n"
00807 "        kLFT=\\E[LEFT;,                                                                  \n"
00808 "        kRIT=\\E[RIGHT;,                                                                 \n"
00809 "        kPRV=\\E[prior;,                                                                 \n"
00810 "        kNXT=\\E[next;,                                                                  \n"
00811 "        kdch1=\\177,                                                                    \n"
00812 "        ri=\\EM, rmacs=^O, rmkx=\\E[?1l\\E>, rmso=\\E[m,                                 \n"
00813 "        rmul=\\E[m,                                                                      \n"
00814 "        rs1=\\E>\\E[1;3;4;5;6l\\E[?7h\\E[m\\E[r\\E[2J\\E[H, rs2=@,                       \n"
00815 "        sc=\\E7,                                                                         \n"
00816 "        sgr=\\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t^N%e^O%;, \n"
00817 "        sgr0=\\E[m, smacs=^N, smkx=\\E[?1h\\E=, smso=\\E[7m,                             \n"
00818 "        smul=\\E[4m, tbc=\\E[3g,                                                         \n"
00819 "        kHOM=\\E[H,                                                                      \n"
00820 "        kEND=\\E[E,                                                                      \n"
00821 ;
00822 #endif
00823 
00824    f.write(terminfo, strlen(terminfo));
00825 
00826    if(f.bad())
00827    {
00828      std::cerr << "Error creating " << filename << std::endl;
00829      exit(1);
00830    }
00831 
00832    f.close();
00833 
00834    std::cerr << "\n\n\n\n"
00835              << "Since this is the first time you have run this program as this\n"
00836              << "user on this host, the special purpose curses TERMINFO database\n"
00837              << "is created for you in \n\n  " 
00838              << dir 
00839              << "/xterm.info\n\n"
00840              << "If you wish to change the keyboard bindings used by curses\n"
00841              << "You can edit that file then remove\n\n  "
00842              <<  dir
00843              << "terminfo/x/xterm\n\n"
00844              << "to get the database automatically rebuilt the next\n"
00845              << "you run this program.\n\n"
00846              ;
00847 
00848    std::cerr << "Press enter to continue:" << std::endl;
00849    std::cerr.flush();
00850    std::cin.get();
00851 
00852    std::cerr << "\n\n\n\n"
00853              << "You should have received documentation about configuring\n"
00854              << "curses with this program.  If you have a source distribution\n"
00855              << "look in the etc sub-directory directory for a README file.\n\n"
00856              << "If you are using an X windows emulator you will need to\n"
00857              << "make sure that your emulator passes the Home, End, Page Up,\n"
00858              << "and Page Down keys through as a string not as functions!\n"
00859              << "You'll also want to make the backspace key send ^H not ^?\n"
00860              << "and perhaps modify your shell startup to use \n\n  "
00861              << "stty erase '^H'\n\n"
00862              ;
00863 
00864    std::cerr << "Press enter to continue:" << std::endl;
00865    std::cerr.flush();
00866    std::cin.get();
00867 
00868    std::cerr << "\n\n\n\n"
00869              << "Note:  you should have received an Xterm file which is used\n"
00870              << "by X windows to define key bindings for your xterm program.\n"
00871              << "If you choose not use the one provided, you must ensure that\n"
00872              << "all the function keys you like using are set up in both\n"
00873              << "$HOME/Xterm and $HOME/.tools_dir/<OS>/xterm.info.\n\n"
00874              << "If your keys still don't work after making sure of all the\n"
00875              << "above, check to see if you are setting your xmodmap key bindings\n"
00876              << "in some way that conflicts with Xterm and xterm.info.\n\nGood luck!\n\n"
00877              ;
00878 
00879 
00880    std::cerr << "Press enter to continue:" << std::endl;
00881    std::cerr.flush();
00882    std::cin.get();
00883 
00884 }
00885 
00886 
00887 
00888 
00889   void create_key_sequences_map()
00890   {
00891     insert_key_sequence(CursesInterface::_map_kf1  , CursorWindow::key_f1);
00892     insert_key_sequence(CursesInterface::_map_kf2  , CursorWindow::key_f2);
00893     insert_key_sequence(CursesInterface::_map_kf3  , CursorWindow::key_f3);
00894     insert_key_sequence(CursesInterface::_map_kf4  , CursorWindow::key_f4);
00895     insert_key_sequence(CursesInterface::_map_kf5  , CursorWindow::key_f5);
00896     insert_key_sequence(CursesInterface::_map_kf6  , CursorWindow::key_f6);
00897     insert_key_sequence(CursesInterface::_map_kf7  , CursorWindow::key_f7);
00898     insert_key_sequence(CursesInterface::_map_kf8  , CursorWindow::key_f8);
00899     insert_key_sequence(CursesInterface::_map_kf9  , CursorWindow::key_f9);
00900     insert_key_sequence(CursesInterface::_map_kf10 , CursorWindow::key_f10);
00901     insert_key_sequence(CursesInterface::_map_kf11 , CursorWindow::key_f11);
00902     insert_key_sequence(CursesInterface::_map_kf12 , CursorWindow::key_f12);
00903     insert_key_sequence(CursesInterface::_map_khom , CursorWindow::key_home);
00904     insert_key_sequence(CursesInterface::_map_kend , CursorWindow::key_end);
00905     insert_key_sequence(CursesInterface::_map_kic  , CursorWindow::key_ic);
00906     insert_key_sequence(CursesInterface::_map_kdc  , CursorWindow::key_dc);
00907     insert_key_sequence(CursesInterface::_map_kpr  , CursorWindow::key_prior);
00908     insert_key_sequence(CursesInterface::_map_knx  , CursorWindow::key_next);
00909     insert_key_sequence(CursesInterface::_map_kup  , CursorWindow::key_up);
00910     insert_key_sequence(CursesInterface::_map_kdn  , CursorWindow::key_down);
00911     insert_key_sequence(CursesInterface::_map_klf  , CursorWindow::key_left);
00912     insert_key_sequence(CursesInterface::_map_krt  , CursorWindow::key_right);
00913     insert_key_sequence(CursesInterface::_map_kbtab, CursorWindow::key_btab);
00914 
00915     {
00916       static char extra_home [] = { 0x1b, '[', 'H', 0 };
00917       static char extra_end  [] = { 0x1b, '[', 'F', 0 };
00918       static char extra_btab [] = { 0x1b, '[', 'Z', 0 };
00919 
00920       insert_key_sequence(extra_home,  CursorWindow::key_home);
00921       insert_key_sequence(extra_end,   CursorWindow::key_end);
00922       insert_key_sequence(extra_btab,  CursorWindow::key_btab);
00923 
00924 
00925       #ifdef __linux
00926       static char extra_bs   [] = { 0x7f, 0 };
00927       insert_key_sequence(extra_bs,    CursorWindow::key_bs);
00928       #else
00929       static char extra_dc   [] = { 0x7f, 0 };
00930       insert_key_sequence(extra_dc,    CursorWindow::key_dc);
00931 
00932       static char extra_dc1   [] = { 0x1b, '[', '3', '~', 0 };
00933       insert_key_sequence(extra_dc1,    CursorWindow::key_dc);
00934 
00935       static char extra_bs   [] = { 0x008, 0 };
00936       insert_key_sequence(extra_bs,    CursorWindow::key_bs);
00937       #endif
00938 
00939     }
00940 
00941     {
00942       static char extra_home1[] = { 0x1b, 'O', 'H', 0 };
00943       static char extra_end1 [] = { 0x1b, 'O', 'F', 0 };
00944       static char extra_btab1[] = { 0x1b, 'O', 'Z', 0 };
00945 
00946 
00947       insert_key_sequence(extra_home1, CursorWindow::key_home);
00948       insert_key_sequence(extra_end1,  CursorWindow::key_end);
00949       insert_key_sequence(extra_btab1, CursorWindow::key_btab);
00950     }
00951 
00952 
00953     {
00954       static char extra_f1[] = { 0x1b, 'O', 'P', 0 };
00955       static char extra_f2[] = { 0x1b, 'O', 'Q', 0 };
00956       static char extra_f3[] = { 0x1b, 'O', 'R', 0 };
00957       static char extra_f4[] = { 0x1b, 'O', 'S', 0 };
00958       static char extra_end  [] = { 0x1b, '[', 'E', 0 };
00959 
00960       insert_key_sequence(extra_f1,  CursorWindow::key_f1);
00961       insert_key_sequence(extra_f2,  CursorWindow::key_f2);
00962       insert_key_sequence(extra_f3,  CursorWindow::key_f3);
00963       insert_key_sequence(extra_f4,  CursorWindow::key_f4);
00964       insert_key_sequence(extra_end,  CursorWindow::key_end);
00965     }
00966 
00967 
00968     {
00969       static char extra_home1[] = { 0x1b, '[', '1', '~', 0 };
00970       static char extra_end1 [] = { 0x1b, '[', '4', '~', 0 };
00971 
00972       insert_key_sequence(extra_home1, CursorWindow::key_home);
00973       insert_key_sequence(extra_end1,  CursorWindow::key_end);
00974     }
00975 
00976 
00977     {
00978       SEARCH search(key_sequences);
00979 
00980       if(!search(0x1b))
00981       {
00982         closeCursesTerminal();
00983         printf("couldn't find the Esc key in the sequence!");
00984         exit(1);
00985       }
00986       ++search;
00987 
00988       if(!search('['))
00989       {
00990         closeCursesTerminal();
00991         printf("couldn't find the '[' key in the!");
00992         exit(1);
00993       }
00994       ++search;
00995 
00996       if(!search('H'))
00997       {
00998         closeCursesTerminal();
00999         printf("couldn't find the 'H' sequence!");
01000         exit(1);
01001       }
01002       ++search;
01003 
01004       int code=0;
01005 
01006       if(!search.finished(&code))
01007       {
01008         closeCursesTerminal();
01009         printf("couldn't find the home sequence!");
01010         exit(1);
01011       }
01012 
01013       if(code != CursorWindow::key_home)
01014       {
01015         closeCursesTerminal();
01016         printf("wrong key code returned");
01017         exit(1);
01018       }
01019 
01020     }
01021 
01022 
01023   }
01024 
01025 
01026   int alarm_occurred=0;
01027 
01028   int read_key_char()
01029     // return a 'char' to the user -- or a 0 that indicates the alarm
01030     // timer fired.
01031   {
01032     char buffer[1];
01033 
01034       while(winch_occurred == 0      &&
01035             read(0, &buffer, 1) < 1  &&
01036             alarm_occurred == 0      
01037 #ifdef __linux
01038             &&
01039             quit_occurred == 0       &&
01040             susp_occurred == 0       &&
01041             int_occurred  == 0
01042 #endif
01043            )
01044       {
01045         usleep(100000);  // sleep 1/10 of a second
01046       }
01047 
01048 
01049     if(alarm_occurred)
01050     {
01051       alarm_occurred = 0;
01052       return 0;
01053     }
01054 
01055     if(winch_occurred)
01056     {
01057         return -1;
01058     }
01059 
01060     alarm_occurred=0;
01061 
01062 #ifdef __linux
01063     if(quit_occurred)
01064     {
01065       quit_occurred=0;
01066       buffer[0] = 0x1c;  // control backslash
01067     }
01068 
01069     if(susp_occurred)
01070     {
01071       susp_occurred=0;
01072       buffer[0] = 0x1a;  // control backslash
01073     }
01074 
01075     if(int_occurred)
01076     {
01077       int_occurred=0;
01078       buffer[0] = 3;   // ^C
01079     }
01080 #endif
01081 
01082 
01083     return buffer[0];
01084 
01085   }
01086 
01087 
01088 #undef refresh
01089 
01090   extern "C" void alarm_handler(int signum)
01091   {
01092      alarm_occurred=1;
01093      signal(SIGALRM, alarm_handler);
01094   }
01095 
01096   extern "C"
01097   {
01098     static void sigwinch_handler(int)
01099     {
01100       winch_occurred=1;
01101       screen_resize_occurred=true;
01102     }
01103   }
01104 
01105 
01106   static std::string _saved;
01107 
01108   int read_mapped_key(CursorWindow &w)
01109     //
01110     // read a key from the keyboard and handle function key sequences
01111     //
01112   {
01113 
01114     if(_saved.size())
01115     {
01116        // keys have been pushed back in the algorithm below
01117        // and we are reading the saved values in subsequent reads
01118 
01119        int rv = _saved[0];
01120 
01121        _saved.erase(_saved.begin());
01122 
01123        return rv;
01124     }
01125 
01126     if(resize_requested)
01127       return -1;
01128 
01129     refresh();
01130 
01131     signal(SIGWINCH, sigwinch_handler);
01132 
01133     signal(SIGALRM, alarm_handler);
01134 
01135 #ifdef __linux
01136     signal(SIGQUIT, quit_handler);
01137     signal(SIGTSTP, susp_handler);
01138     signal(SIGINT, int_handler);
01139 #endif
01140 
01141     SEARCH search_term = key_sequences;
01142 
01143 
01144     int c;
01145 
01146     int code;
01147 
01148 
01149     for(;;)
01150     {
01151       sigprocmask(SIG_UNBLOCK, &winch_blocker, 0); // enable window change signals
01152 
01153       c = read_key_char();
01154 
01155 
01156       sigprocmask(SIG_BLOCK, &winch_blocker, 0); // disable window change signals
01157 
01158       if(c == 0x1b)
01159       {
01160          // escape is never the middle character in a sequence
01161          alarm_occurred=0;
01162          ualarm(900000,0);  // cause the next read to type out
01163                             // the timeout is 0.9 seconds.  ualarm on UBUNTU
01164                             // malfunctions for 1.0 and higher...
01165 
01166       }
01167       else
01168       {
01169          ualarm(0,0);  // turn off any pending alarm
01170 
01171       }
01172 
01173       if(winch_occurred || resize_requested || c == -1)
01174       {
01175         _saved.resize(0);
01176         
01177         closeCursesTerminal();
01178         openCursesTerminal();
01179         refresh();
01180         
01181         return -1;
01182       }
01183 
01184       if( c == 0  || !search_term(c) )
01185       {
01186         // either we have a read time out or this key isn't part of
01187         // a valid sequence
01188 
01189         if(c == 0x1b)
01190         {
01191           // escape is never found in the middle of a sequence
01192         
01193           if( _saved.size() && _saved[0] == 0x1b )
01194           {
01195             // discard the previous sequence and let this start a new one
01196         
01197             SEARCH new_term = key_sequences;
01198         
01199             new_term(c);
01200 
01201             ++new_term;
01202         
01203             search_term = new_term;
01204         
01205             _saved.resize(0);
01206             _saved += (char)(0x1b);
01207 
01208             continue;
01209         
01210           }
01211         
01212         }
01213 
01214         if(c != 0)
01215           _saved += (char)(c);
01216 
01217         if(_saved.size())
01218         {
01219           int rv = _saved[0];
01220 
01221           _saved.erase(_saved.begin());
01222 
01223           return rv;
01224         }
01225 
01226         continue;  // if no chars read, keep reading
01227       }
01228 
01229       ++search_term;
01230 
01231       _saved += (char)(c);
01232 
01233       if(search_term.finished(&code))
01234       {
01235         _saved.resize(0);
01236         return code;
01237       }
01238     }
01239 
01240   }
01241 
01242 };
01243 
01244 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3