home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tv20cpp.zip / src / system.cc < prev    next >
C/C++ Source or Header  |  1999-05-19  |  60KB  |  2,308 lines

  1. /*
  2.  * system.cc
  3.  *
  4.  * Copyright (c) 1997 Sergio Sigala, Brescia, Italy.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  */
  27.  
  28. /* Modified by Sergey Clushin <serg@lamport.ru>, <Clushin@deol.ru> */
  29. /* Modified by Dmitrij Korovkin <tkf@glasnet.ru> */
  30.  
  31. #define Uses_TButton
  32. #define Uses_TColorSelector
  33. #define Uses_TDeskTop
  34. #define Uses_TDirListBox
  35. #define Uses_TDrawBuffer
  36. #define Uses_TEvent
  37. #define Uses_TEventQueue
  38. #define Uses_TFrame
  39. #define Uses_THistory
  40. #define Uses_TIndicator
  41. #define Uses_TKeys
  42. #define Uses_TListViewer
  43. #define Uses_TMenuBox
  44. #define Uses_TOutlineViewer
  45. #define Uses_TScreen
  46. #define Uses_TScrollBar
  47. #define Uses_TStatusLine
  48. #include <tvision/tv.h>
  49.  
  50. #include <ctype.h>
  51. #include <fcntl.h>
  52. #include <fstream.h>
  53. #include <iostream.h>
  54. #include <signal.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include <sys/stat.h>
  59. #include <sys/time.h>
  60. #include <unistd.h>
  61.  
  62. #include <config.h>        /* configuration file */
  63.  
  64. #ifdef ENABLE_FBSDM
  65.     /* #include <machine/console.h> */
  66.     #define CONS_MOUSECTL    _IOWR('c', 10, mouse_info_t)
  67.     #define    RIGHT_BUTTON        0x01
  68.     #define    MIDDLE_BUTTON        0x02
  69.     #define    LEFT_BUTTON        0x04
  70.     struct mouse_data {
  71.         int    x;
  72.         int     y;
  73.         int     buttons;
  74.     };
  75.     struct mouse_mode {
  76.         int    mode;
  77.         int    signal;
  78.     };
  79.     #define MOUSE_SHOW        0x01
  80.     #define MOUSE_HIDE        0x02
  81.     #define MOUSE_MOVEABS        0x03
  82.     #define MOUSE_MOVEREL        0x04
  83.     #define MOUSE_GETINFO        0x05
  84.     #define MOUSE_MODE        0x06
  85.     #define MOUSE_ACTION        0x07
  86.     struct mouse_info {
  87.         int    operation;
  88.         union {
  89.             struct mouse_data data;
  90.             struct mouse_mode mode;
  91.         }u;
  92.     };
  93.     typedef struct mouse_info mouse_info_t;
  94. #endif
  95.  
  96. extern "C"
  97. {
  98. #ifdef HAVE_NCURSES_H
  99. #include <ncurses.h>
  100. #else
  101. #include <curses.h>
  102. #endif
  103.  
  104. #ifdef HAVE_GPM_H
  105. #include <gpm.h>    /* mouse stuff */
  106. #endif
  107. };
  108.  
  109. #ifdef __linux__
  110. #include <sys/kd.h>    /* keyboard stuff */
  111. #endif
  112.  
  113. #include <term.h>
  114. #undef buttons        /* delete this line and see what happens :-) */
  115.  
  116. /*
  117.  * This is the delay in ms before the first evMouseAuto is generated when the
  118.  * user holds down a mouse button.
  119.  */
  120. #define DELAY_AUTOCLICK_FIRST    400
  121.  
  122. /*
  123.  * This is the delay in ms between next evMouseAuto events.  Must be greater
  124.  * than DELAY_SIGALRM (see below).
  125.  */
  126. #define DELAY_AUTOCLICK_NEXT    100
  127.  
  128. /*
  129.  * This is the time limit in ms within button presses are recognized as
  130.  * double-click events.  Used only under FreeBSD because Gpm has its own
  131.  * double-click detecting machanism.
  132.  */
  133. #define DELAY_DOUBLECLICK    300
  134.  
  135. /*
  136.  * This is the time limit in ms within Esc-key sequences are detected as
  137.  * Alt-letter sequences.  Useful when we can't generate Alt-letter sequences
  138.  * directly.
  139.  */
  140. #define DELAY_ESCAPE        400
  141.  
  142. /*
  143.  * This is the delay in ms between consecutive SIGALRM signals.  This
  144.  * signal is used to generate evMouseAuto and cmSysWakeup events.
  145.  */
  146. #define DELAY_SIGALRM        100
  147.  
  148. /*
  149.  * This broadcast event is used to update the StatusLine.
  150.  */
  151. #define DELAY_WAKEUP        200
  152.  
  153. /*
  154.  * FreeBSD mouse system only: define which signal to use.
  155.  */
  156. #define FBSDM_SIGNAL        SIGUSR1
  157.  
  158. /* key modifiers */
  159.  
  160. #define MALT        (kbLeftAlt | kbRightAlt)
  161. #define MCTRL        (kbLeftCtrl | kbRightCtrl)
  162. #define MSHIFT        (kbLeftShift | kbRightShift)
  163.  
  164. /* key types */
  165.  
  166. #define TALT        0x01        /* alt-letter key */
  167.  
  168. typedef struct
  169. {
  170.     int in;
  171.     char type;
  172.     char modifiers;
  173.     short out;
  174. }
  175. keym_t;
  176.  
  177. static keym_t keym[] =
  178. {
  179.     /* ascii codes */
  180.  
  181.     {   1, 0, 0, kbCtrlA }, {  2, 0, 0, kbCtrlB }, {  3, 0, 0, kbCtrlC },
  182.     {   4, 0, 0, kbCtrlD }, {  5, 0, 0, kbCtrlE }, {  6, 0, 0, kbCtrlF },
  183.     {   7, 0, 0, kbCtrlG }, {  8, 0, 0, kbCtrlH }, {  9, 0, 0, kbCtrlI },
  184.     {  10, 0, 0, kbCtrlJ }, { 11, 0, 0, kbCtrlK }, { 12, 0, 0, kbCtrlL },
  185.     {  13, 0, 0, kbCtrlM }, { 14, 0, 0, kbCtrlN }, { 15, 0, 0, kbCtrlO },
  186.     {  16, 0, 0, kbCtrlP }, { 17, 0, 0, kbCtrlQ }, { 18, 0, 0, kbCtrlR },
  187.     {  19, 0, 0, kbCtrlS }, { 20, 0, 0, kbCtrlT }, { 21, 0, 0, kbCtrlU },
  188.     {  22, 0, 0, kbCtrlV }, { 23, 0, 0, kbCtrlW }, { 24, 0, 0, kbCtrlX },
  189.     {  25, 0, 0, kbCtrlY }, { 26, 0, 0, kbCtrlZ }, {  9, 0, 0, kbTab   },
  190.     {  13, 0, 0, kbEnter }, { 27, 0, 0, kbEsc   }, { 31, 0, 0, kbCtrlBack },
  191.     { 127, 0, 0, kbBack  },
  192.     {  10, 0, 0, kbEnter },    /* I need this */
  193.  
  194.     { 9, 0, MSHIFT, kbShiftTab },
  195.  
  196.     /* alt-letter codes */
  197.  
  198.     { 8, TALT, 0, kbAltBack }, { ' ', TALT, 0, kbAltSpace },
  199.     { '0', TALT, 0, kbAlt0 }, { '1', TALT, 0, kbAlt1 }, { '2', TALT, 0, kbAlt2 },
  200.     { '3', TALT, 0, kbAlt3 }, { '4', TALT, 0, kbAlt4 }, { '5', TALT, 0, kbAlt5 },
  201.     { '6', TALT, 0, kbAlt6 }, { '7', TALT, 0, kbAlt7 }, { '8', TALT, 0, kbAlt8 },
  202.     { '9', TALT, 0, kbAlt9 },
  203.     { 'A', TALT, 0, kbAltA }, { 'B', TALT, 0, kbAltB }, { 'C', TALT, 0, kbAltC },
  204.     { 'D', TALT, 0, kbAltD }, { 'E', TALT, 0, kbAltE }, { 'F', TALT, 0, kbAltF },
  205.     { 'G', TALT, 0, kbAltG }, { 'H', TALT, 0, kbAltH }, { 'I', TALT, 0, kbAltI },
  206.     { 'J', TALT, 0, kbAltJ }, { 'K', TALT, 0, kbAltK }, { 'L', TALT, 0, kbAltL },
  207.     { 'M', TALT, 0, kbAltM }, { 'N', TALT, 0, kbAltN }, { 'O', TALT, 0, kbAltO },
  208.     { 'P', TALT, 0, kbAltP }, { 'Q', TALT, 0, kbAltQ }, { 'R', TALT, 0, kbAltR },
  209.     { 'S', TALT, 0, kbAltS }, { 'T', TALT, 0, kbAltT }, { 'U', TALT, 0, kbAltU },
  210.     { 'V', TALT, 0, kbAltV }, { 'W', TALT, 0, kbAltW }, { 'X', TALT, 0, kbAltX },
  211.     { 'Y', TALT, 0, kbAltY }, { 'Z', TALT, 0, kbAltZ }, { 127, TALT, 0, kbAltBack },
  212.  
  213.     /* escape codes */
  214.  
  215.     { KEY_DOWN,  0, 0, kbDown  }, { KEY_UP,   0, 0, kbUp  }, { KEY_LEFT,  0, 0, kbLeft },
  216.     { KEY_RIGHT, 0, 0, kbRight }, { KEY_HOME, 0, 0, kbHome },
  217.     { KEY_BACKSPACE, 0, 0, kbBack }, { KEY_F(1), 0, 0, kbF1 },
  218.     { KEY_F(2),  0, 0, kbF2    }, { KEY_F(3), 0, 0, kbF3  }, { KEY_F(4),  0, 0, kbF4 },
  219.     { KEY_F(5),  0, 0, kbF5    }, { KEY_F(6), 0, 0, kbF6  }, { KEY_F(7),  0, 0, kbF7 },
  220.     { KEY_F(8),  0, 0, kbF8    }, { KEY_F(9), 0, 0, kbF9  }, { KEY_F(10), 0, 0, kbF10 },
  221.     { KEY_DC,    0, 0, kbDel   }, { KEY_IC,   0, 0, kbIns }, { KEY_NPAGE, 0, 0, kbPgDn },
  222.     { KEY_PPAGE, 0, 0, kbPgUp  }, { KEY_END,  0, 0, kbEnd },
  223.  
  224.     { KEY_LEFT, 0, MCTRL, kbCtrlLeft }, { KEY_RIGHT, 0, MCTRL, kbCtrlRight },
  225.     { KEY_HOME, 0, MCTRL, kbCtrlHome }, { KEY_F(1), 0, MCTRL, kbCtrlF1 },
  226.     { KEY_F(2), 0, MCTRL, kbCtrlF2 }, { KEY_F(3), 0, MCTRL, kbCtrlF3 },
  227.     { KEY_F(4), 0, MCTRL, kbCtrlF4 }, { KEY_F(5), 0, MCTRL, kbCtrlF5 },
  228.     { KEY_F(6), 0, MCTRL, kbCtrlF6 }, { KEY_F(7), 0, MCTRL, kbCtrlF7 },
  229.     { KEY_F(8), 0, MCTRL, kbCtrlF8 }, { KEY_F(9), 0, MCTRL, kbCtrlF9 },
  230.     { KEY_F(10), 0, MCTRL, kbCtrlF10 }, { KEY_DC, 0, MCTRL, kbCtrlDel },
  231.     { KEY_IC, 0, MCTRL, kbCtrlIns }, { KEY_NPAGE, 0, MCTRL, kbCtrlPgDn },
  232.     { KEY_PPAGE, 0, MCTRL, kbCtrlPgUp }, { KEY_END, 0, MCTRL, kbCtrlEnd },
  233.  
  234.     { KEY_F(1), 0, MALT, kbAltF1 }, { KEY_F(2), 0, MALT, kbAltF2 },
  235.     { KEY_F(3), 0, MALT, kbAltF3 }, { KEY_F(4), 0, MALT, kbAltF4 },
  236.     { KEY_F(5), 0, MALT, kbAltF5 }, { KEY_F(6), 0, MALT, kbAltF6 },
  237.     { KEY_F(7), 0, MALT, kbAltF7 }, { KEY_F(8), 0, MALT, kbAltF8 },
  238.     { KEY_F(9), 0, MALT, kbAltF9 }, { KEY_F(10), 0, MALT, kbAltF10 },
  239.  
  240.     { KEY_F(11), 0, MSHIFT, kbShiftF1 }, { KEY_F(12), 0, MSHIFT, kbShiftF2 },
  241.     { KEY_F(13), 0, MSHIFT, kbShiftF3 }, { KEY_F(14), 0, MSHIFT, kbShiftF4 },
  242.     { KEY_F(15), 0, MSHIFT, kbShiftF5 }, { KEY_F(16), 0, MSHIFT, kbShiftF6 },
  243.     { KEY_F(17), 0, MSHIFT, kbShiftF7 }, { KEY_F(18), 0, MSHIFT, kbShiftF8 },
  244.     { KEY_F(19), 0, MSHIFT, kbShiftF9 }, { KEY_F(20), 0, MSHIFT, kbShiftF10 },
  245.     { KEY_DC,    0, MSHIFT, kbShiftDel }, { KEY_IC, 0, MSHIFT, kbShiftIns },
  246.  
  247.     /* Shift'ed codes in xterm */
  248.  
  249.     { KEY_F(13), 0, 0, kbShiftF1 }, { KEY_F(14), 0, 0, kbShiftF2 },
  250.     { KEY_F(15), 0, 0, kbShiftF3 }, { KEY_F(16), 0, 0, kbShiftF4 },
  251.     { KEY_F(17), 0, 0, kbShiftF5 }, { KEY_F(18), 0, 0, kbShiftF6 },
  252.     { KEY_F(19), 0, 0, kbShiftF7 }, { KEY_F(20), 0, 0, kbShiftF8 },
  253.     { KEY_F(21), 0, 0, kbShiftF9 }, { KEY_F(22), 0, 0, kbShiftF10 },
  254.  
  255.     /* Ctrl'ed codes in xterm */
  256.  
  257.     { KEY_F(25), 0, 0, kbCtrlF1 }, { KEY_F(26), 0, 0, kbCtrlF2 },
  258.     { KEY_F(27), 0, 0, kbCtrlF3 }, { KEY_F(28), 0, 0, kbCtrlF4 },
  259.     { KEY_F(29), 0, 0, kbCtrlF5 }, { KEY_F(30), 0, 0, kbCtrlF6 },
  260.     { KEY_F(31), 0, 0, kbCtrlF7 }, { KEY_F(32), 0, 0, kbCtrlF8 },
  261.     { KEY_F(33), 0, 0, kbCtrlF9 }, { KEY_F(34), 0, 0, kbCtrlF10 },
  262.     { KEY_LL, 0, 0, kbCtrlPgDn }, { KEY_BEG, 0, 0, kbCtrlPgUp },
  263.     { KEY_COPY, 0, 0, kbCtrlIns }, { KEY_SBEG, 0, 0, kbShiftIns },
  264.  
  265.     /* Alt'ed (Meta'ed) codes in xterm */
  266.  
  267.     { KEY_F(37), 0, 0, kbAltF1 }, { KEY_F(38), 0, 0, kbAltF2 },
  268.     { KEY_F(39), 0, 0, kbAltF3 }, { KEY_F(40), 0, 0, kbAltF4 },
  269.     { KEY_F(41), 0, 0, kbAltF5 }, { KEY_F(42), 0, 0, kbAltF6 },
  270.     { KEY_F(43), 0, 0, kbAltF7 }, { KEY_F(44), 0, 0, kbAltF8 },
  271.     { KEY_F(45), 0, 0, kbAltF9 }, { KEY_F(46), 0, 0, kbAltF10 }
  272. };
  273.  
  274. /* lookup table for KOI8-R to CP866 encoding */
  275. #if 0
  276. static unsigned char cyrillicTable[128] =
  277. {
  278.     176, 177, 178, 179, 180, 181, 182, 183,    /* 0x80 - 0x87 */
  279.     184, 185, 250, 187, 188, 189, 190, 191,    /* 0x88 - 0x8f */
  280.     192, 193, 194, 195, 196, 197, 198, 199,    /* 0x90 - 0x97 */
  281.     200, 201, 202, 255, 204, 205, 206, 207,    /* 0x98 - 0x9f */
  282.     208, 209, 210, 241, 212, 213, 214, 215,    /* 0xa0 - 0xa7 */
  283.     216, 217, 218, 219, 220, 221, 222, 223,    /* 0xa8 - 0xaf */
  284.     211, 243, 242, 240, 244, 245, 246, 247,    /* 0xb0 - 0xb7 */
  285.     248, 249, 186, 251, 252, 253, 254, 203,    /* 0xb8 - 0xbf */
  286.     238, 160, 161, 230, 164, 165, 228, 163,    /* 0xc0 - 0xc7 */
  287.     229, 168, 169, 170, 171, 172, 173, 174,    /* 0xc8 - 0xcf */
  288.     175, 239, 224, 225, 226, 227, 166, 162,    /* 0xd0 - 0xd7 */
  289.     236, 235, 167, 232, 237, 233, 231, 234,    /* 0xd8 - 0xdf */
  290.     158, 128, 129, 150, 132, 133, 148, 131,    /* 0xe0 - 0xe7 */
  291.     149, 136, 137, 138, 139, 140, 141, 142,    /* 0xe8 - 0xef */
  292.     143, 159, 144, 145, 146, 147, 134, 130,    /* 0xf0 - 0xf7 */
  293.     156, 155, 135, 152, 157, 153, 151, 154    /* 0xf8 - 0xff */
  294. };
  295. #endif
  296.  
  297. static unsigned char cyrillicTable[128] =
  298. {
  299.     192, 193, 194, 195, 196, 197, 198, 199, /* 0x80 - 0x87 */ 
  300.     200, 201, 202, 203, 204, 205 ,206, 207, /* 0x88 - 0x8f */
  301.     208, 209, 210, 211, 212, 213, 214, 215, /* 0x90 - 0x97 */
  302.     216, 217, 218, 219, 220, 221, 222, 223, /* 0x98 - 0x9f */
  303.     240, 241, 242, 243, 244, 245, 246, 247, /* 0xa0 - 0xa7 */
  304.     248, 249, 250, 251, 252, 253, 254, 255, /* 0xa8 - 0xaf */
  305.     176, 177, 178, 179, 180, 181, 182, 183, /* 0xb0 - 0xb7 */
  306.     184, 185, 186, 187, 188, 189, 190, 191, /* 0xb8 - 0xbf */
  307.     238, 160, 161, 230, 164, 165, 228, 163,    /* 0xc0 - 0xc7 */
  308.     229, 168, 169, 170, 171, 172, 173, 174,    /* 0xc8 - 0xcf */
  309.     175, 239, 224, 225, 226, 227, 166, 162,    /* 0xd0 - 0xd7 */
  310.     236, 235, 167, 232, 237, 233, 231, 234,    /* 0xd8 - 0xdf */
  311.     158, 128, 129, 150, 132, 133, 148, 131,    /* 0xe0 - 0xe7 */
  312.     149, 136, 137, 138, 139, 140, 141, 142,    /* 0xe8 - 0xef */
  313.     143, 159, 144, 145, 146, 147, 134, 130,    /* 0xf0 - 0xf7 */
  314.     156, 155, 135, 152, 157, 153, 151, 154    /* 0xf8 - 0xff */
  315. };
  316.     
  317. /* lookup table for LATIN1 to CP437 enconding */
  318.  
  319. static unsigned char latinTable[128] =
  320. {
  321.     199, 252, 233, 226, 228, 224, 229, 231, /* 0x80 - 0x87 */
  322.     234, 235, 232, 239, 238, 236, 196, 197, /* 0x88 - 0x8f */
  323.     201, 230, 198, 244, 247, 242, 251, 183, /* 0x90 - 0x97 */
  324.     225, 214, 220, 243, 250, 209, 158, 159, /* 0x98 - 0x9f */
  325.     255, 173, 155, 156, 177, 157, 188, 186, /* 0xa0 - 0xa7 */
  326.     191, 169, 166, 174, 170, 237, 189, 187, /* 0xa8 - 0xaf */
  327.     176, 241, 253, 179, 180, 181, 182, 249, /* 0xb0 - 0xb7 */
  328.     184, 185, 167, 175, 172, 171, 190, 168, /* 0xb8 - 0xbf */
  329.     192, 193, 194, 195, 142, 143, 146, 128, /* 0xc0 - 0xc7 */
  330.     200, 144, 202, 203, 204, 205, 206, 207, /* 0xc8 - 0xcf */
  331.     208, 165, 210, 211, 212, 213, 153, 215, /* 0xd0 - 0xd7 */
  332.     216, 217, 218, 219, 154, 221, 222, 223, /* 0xd8 - 0xdf */
  333.     133, 160, 131, 227, 132, 134, 145, 135, /* 0xe0 - 0xe7 */
  334.     138, 130, 136, 137, 141, 161, 140, 139, /* 0xe8 - 0xef */
  335.     240, 164, 149, 162, 147, 245, 148, 246, /* 0xf0 - 0xf7 */
  336.     248, 151, 163, 150, 129, 178, 254, 152, /* 0xf8 - 0xff */
  337. };
  338.  
  339. /* lookup table to translate characters from pc set to standard ascii */
  340.  
  341. static unsigned pcToAscii[256] =
  342. {
  343.     /* first block of non-ascii characters from 0 to 31 */
  344.  
  345.     32,    /* 0 */
  346.     79,    /* 1 */
  347.     79,    /* 2 */
  348.     111,    /* 3 */
  349.     111,    /* 4 */
  350.     111,    /* 5 */
  351.     111,    /* 6 */
  352.     111,    /* 7 */
  353.     111,    /* 8 */
  354.     111,    /* 9 */
  355.     111,    /* 10 */
  356.     111,    /* 11 */
  357.     33,    /* 12 */
  358.     33,    /* 13 */
  359.     33,    /* 14 */
  360.     42,    /* 15 */
  361.     62,    /* 16 */
  362.     60,    /* 17 */
  363.     124,    /* 18 */
  364.     33,    /* 19 */
  365.     33,    /* 20 */
  366.     79,    /* 21 */
  367.     95,    /* 22 */
  368.     124,    /* 23 */
  369.     94,    /* 24 */
  370.     86,    /* 25 */
  371.     62,    /* 26 */
  372.     60,    /* 27 */
  373.     45,    /* 28 */
  374.     45,    /* 29 */
  375.     94,    /* 30 */
  376.     86,    /* 31 */
  377.  
  378.     /* ascii characters from 32 to 126 */
  379.  
  380.     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
  381.     49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
  382.     66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
  383.     83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
  384.     100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
  385.     114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
  386.  
  387.     /* second block of non-ascii characters from 127 to 255 */
  388.  
  389. #ifdef DISABLE_8BIT_CHARS
  390.     100,    /* 127 */
  391.     99,    /* 128 */
  392.     117,    /* 129 */
  393.     101,    /* 130 */
  394.     97,    /* 131 */
  395.     97,    /* 132 */
  396.     97,    /* 133 */
  397.     97,    /* 134 */
  398.     99,    /* 135 */
  399.     101,    /* 136 */
  400.     101,    /* 137 */
  401.     101,    /* 138 */
  402.     105,    /* 139 */
  403.     105,    /* 140 */
  404.     105,    /* 141 */
  405.     97,    /* 142 */
  406.     97,    /* 143 */
  407.     101,    /* 144 */
  408.     97,    /* 145 */
  409.     102,    /* 146 */
  410.     111,    /* 147 */
  411.     111,    /* 148 */
  412.     111,    /* 149 */
  413.     117,    /* 150 */
  414.     117,    /* 151 */
  415.     121,    /* 152 */
  416.     79,    /* 153 */
  417.     85,    /* 154 */
  418.     99,    /* 155 */
  419.     76,    /* 156 */
  420.     89,    /* 157 */
  421.     80,    /* 158 */
  422.     102,    /* 159 */
  423.     97,    /* 160 */
  424.     105,    /* 161 */
  425.     111,    /* 162 */
  426.     117,    /* 163 */
  427.     110,    /* 164 */
  428.     78,    /* 165 */
  429.     45,    /* 166 */
  430.     45,    /* 167 */
  431.     63,    /* 168 */
  432.     45,    /* 169 */
  433.     45,    /* 170 */
  434.     47,    /* 171 */
  435.     47,    /* 172 */
  436.     33,    /* 173 */
  437.     60,    /* 174 */
  438.     62,    /* 175 */
  439.     58,    /* 176 */
  440.     37,    /* 177 */
  441.     37,    /* 178 */
  442.     124,    /* 179 */
  443.     123,    /* 180 */
  444.     43,    /* 181 */
  445.     43,    /* 182 */
  446.     43,    /* 183 */
  447.     43,    /* 184 */
  448.     43,    /* 185 */
  449.     73,    /* 186 */
  450.     43,    /* 187 */
  451.     39,    /* 188 */
  452.     43,    /* 189 */
  453.     43,    /* 190 */
  454.     46,    /* 191 */
  455.     96,    /* 192 */
  456.     43,    /* 193 */
  457.     43,    /* 194 */
  458.     125,    /* 195 */
  459.     45,    /* 196 */
  460.     43,    /* 197 */
  461.     43,    /* 198 */
  462.     43,    /* 199 */
  463.     96,    /* 200 */
  464.     46,    /* 201 */
  465.     43,    /* 202 */
  466.     43,    /* 203 */
  467.     43,    /* 204 */
  468.     61,    /* 205 */
  469.     43,    /* 206 */
  470.     43,    /* 207 */
  471.     43,    /* 208 */
  472.     43,    /* 209 */
  473.     43,    /* 210 */
  474.     43,    /* 211 */
  475.     43,    /* 212 */
  476.     43,    /* 213 */
  477.     43,    /* 214 */
  478.     43,    /* 215 */
  479.     43,    /* 216 */
  480.     39,    /* 217 */
  481.     46,    /* 218 */
  482.     124,    /* 219 */
  483.     45,    /* 220 */
  484.     124,    /* 221 */
  485.     124,    /* 222 */
  486.     45,    /* 223 */
  487.     97,    /* 224 */
  488.     98,    /* 225 */
  489.     105,    /* 226 */
  490.     112,    /* 227 */
  491.     101,    /* 228 */
  492.     111,    /* 229 */
  493.     117,    /* 230 */
  494.     121,    /* 231 */
  495.     111,    /* 232 */
  496.     111,    /* 233 */
  497.     111,    /* 234 */
  498.     111,    /* 235 */
  499.     111,    /* 236 */
  500.     111,    /* 237 */
  501.     69,    /* 238 */
  502.     110,    /* 239 */
  503.     61,    /* 240 */
  504.     43,    /* 241 */
  505.     62,    /* 242 */
  506.     60,    /* 243 */
  507.     40,    /* 244 */
  508.     41,    /* 245 */
  509.     45,    /* 246 */
  510.     61,    /* 247 */
  511.     111,    /* 248 */
  512.     46,    /* 249 */
  513.     46,    /* 250 */
  514.     86,    /* 251 */
  515.     110,    /* 252 */
  516.     50,    /* 253 */
  517.     88,    /* 254 */
  518.     32    /* 255 */
  519.     /*
  520.      * Added as a plug for compatibility with the old applications.
  521.      */
  522. #elif defined(ENABLE_RUSSIAN_CHARSET)
  523.     32,
  524.     225, 226, 247, 231, 228, 229, 246, 250, 233,
  525.     234, 235, 236, 237, 238, 239, 240, 242, 243, 
  526.     244, 245, 230, 232, 227, 254, 251, 253, 223, 
  527.     249, 248, 252, 224, 241, 193, 194, 215, 199, 
  528.     196, 197, 214, 218, 201, 202, 203, 204, 205,
  529.     206, 207, 208, 177, 177, 178, 179, 180, 181,
  530.     182, 183, 184, 185, 186, 187, 188, 189, 190,
  531.     191, 192, 193, 194, 195, 196, 197, 198, 199,
  532.     200, 201, 202, 203, 204, 205, 206, 207, 208, 
  533.     209, 210, 211, 212, 213, 214, 215, 216, 217,
  534.     218, 219, 220, 221, 222, 223, 210, 211, 212,
  535.     213, 198, 200, 195, 222, 219, 221, 223, 217,
  536.     216, 220, 192, 209, 160, 161, 162, 163 ,164,
  537.     165, 166, 167, 168, 169, 170, 171, 172 ,173,
  538.     174, 174
  539. #else
  540.     32,
  541.     128, 129, 130, 131, 132, 133, 134, 135,
  542.     136, 137, 138, 139, 140, 141, 142, 143,
  543.     144, 145, 146, 147, 148, 149, 150, 151,
  544.     152, 153, 154, 155, 156, 157, 158, 159,
  545.     160, 161, 162, 163, 164, 165, 166, 167,
  546.     168, 169, 170, 171, 172, 173, 174, 175,
  547.     176, 177, 178, 179, 180, 181, 182, 183,
  548.     184, 185, 186, 187, 188, 189, 190, 191,
  549.     192, 193, 194, 195, 196, 197, 198, 199,
  550.     200, 201, 202, 203, 204, 205, 206, 207,
  551.     208, 209, 210, 211, 212, 213, 214, 215,
  552.     216, 217, 218, 219, 220, 221, 222, 223,
  553.     224, 225, 226, 227, 228, 229, 230, 231,
  554.     232, 233, 234, 235, 236, 237, 238, 239,
  555.     240, 241, 242, 243, 244, 245, 246, 247,
  556.     248, 249, 250, 251, 252, 253, 254, 255
  557. #endif
  558. };
  559.  
  560. /* this array stores the corresponding ncurses attribute for each TV color */
  561.  
  562. static unsigned attributeMap[256];
  563.  
  564. ushort TEventQueue::doubleDelay = 8;
  565. Boolean TEventQueue::mouseReverse = False;
  566.  
  567. ushort TScreen::screenMode;
  568. uchar TScreen::screenWidth;
  569. uchar TScreen::screenHeight;
  570. ushort *TScreen::screenBuffer;
  571.  
  572. static TEvent *evIn;        /* message queue system */
  573. static TEvent *evOut;
  574. static TEvent evQueue[eventQSize];
  575. static TPoint msWhere;        /* mouse coordinates */
  576. static char env[PATH_MAX];    /* value of the TVOPT environment variable */
  577. static fd_set fdSet;        /* used for select() */
  578. static int curX, curY;        /* current cursor coordinates */
  579. static int currentTime;        /* current timer value */
  580. static int doRepaint;        /* should redraw the screen ? */
  581. static int doResize;        /* resize screen ? */
  582. static int evLength;        /* number of events in the queue */
  583. static int msOldButtons;    /* mouse button status */
  584. static ofstream xlog;        /* a logging file */
  585.  
  586. /*
  587.  * A simple class which implements a timer.
  588.  */
  589.  
  590. class Timer
  591. {
  592.     int limit;
  593. public:
  594.     Timer() { limit = -1; }
  595.     int isExpired() { return limit != -1 && currentTime >= limit; }
  596.     int isRunning() { return limit != -1; }
  597.     void start(int timeout) { limit = currentTime + timeout; }
  598.     void stop() { limit = -1; }
  599. };
  600.  
  601. static Timer kbEscTimer;    /* time limit to detect Esc-key sequences */
  602. static Timer msAutoTimer;    /* time when generate next cmMouseAuto */
  603. static Timer wakeupTimer;    /* time when generate next cmWakeup */
  604.  
  605. #ifdef ENABLE_FBSDM
  606. static Timer msDoubleTimer;    /* time limit to detect double-click events */
  607. static int msFlag;        /* set if there are mouse events */
  608. static int msUseArrow;        /* use arrow pointer */
  609. #endif
  610.  
  611. #ifdef HAVE_GPM_H
  612. static int msFd;        /* mouse file descriptor */
  613. #endif
  614.  
  615. #ifdef ENABLE_VCS
  616. int vcsFd;            /* virtual console system descriptor */
  617. unsigned char *vcsMap;        /* define which character table to use */
  618. #endif
  619.  
  620. /*
  621.  * GENERAL FUNCTIONS
  622.  */
  623.  
  624. #define LOG(s) xlog << s << endl
  625.  
  626. inline int range(int test, int min, int max)
  627. {
  628.     return test < min ? min : test > max ? max : test;
  629. }
  630.  
  631. /*
  632.  * KEYBOARD FUNCTIONS
  633.  */
  634.  
  635. /*
  636.  * Builds a keycode from code and modifiers.
  637.  */
  638.  
  639. static int kbMapKey(int code, int type, int modifiers)
  640. {
  641.     keym_t *best = NULL, *p;
  642.  
  643.     for (p = keym; p < keym + sizeof(keym) / sizeof(keym_t); p++)
  644.     {
  645.         /* code and type must match */
  646.  
  647.         if (p->in == code && p->type == type)
  648.         {
  649.             /*
  650.              * now get the best keycode we have, modifier keys
  651.              * may differ
  652.              */
  653.             if (best == NULL || p->modifiers == modifiers)
  654.             {
  655.                 best = p;
  656.             }
  657.         }
  658.     }
  659.     if (best != NULL) return best->out;    /* keycode found */
  660.     if (code <= 255) return code;    /* it is an ascii character */
  661.     return kbNoKey;        /* unknown code */
  662. }
  663.  
  664. /*
  665.  * Gets information about modifier keys (Alt, Ctrl and Shift).  This can
  666.  * be done only if the program runs on the system console.
  667.  */
  668.  
  669. static int kbReadShiftState()
  670. {
  671. #ifdef __linux__
  672.     unsigned char arg = 6;    /* TIOCLINUX function #6 */
  673.     int shift = 0;
  674.  
  675.     if (ioctl(STDIN_FILENO, TIOCLINUX, &arg) != -1)
  676.     {
  677.         if (arg & (2 | 8)) shift |= kbLeftAlt | kbRightAlt;
  678.         if (arg & 4) shift |= kbLeftCtrl | kbRightCtrl;
  679.         if (arg & 1) shift |= kbLeftShift | kbRightShift;
  680.     }
  681.     return shift;
  682. #else
  683.     return 0;
  684. #endif
  685. }
  686.  
  687. /*
  688.  * Reads a key from the keyboard.
  689.  */
  690. #ifdef NCURSES_MOUSE_VERSION
  691. static void msHandle();
  692. #endif
  693.  
  694. static void kbHandle()
  695. {
  696.     int code, type = 0;
  697.     sigset_t alarmBlock, normalMask;
  698.  
  699.     sigemptyset(&alarmBlock);
  700.     sigaddset(&alarmBlock, SIGALRM);
  701.  
  702.     /* see if there is data available */
  703.  
  704.     sigprocmask(SIG_BLOCK, &alarmBlock, &normalMask);
  705.     code = getch();
  706.     sigprocmask(SIG_SETMASK, &normalMask, NULL);
  707.  
  708.     if (code != ERR)    /* was it a key press ? */
  709.     {
  710.         /* grab the escape key and start the timer */
  711.  
  712.         if (code == 27 && !kbEscTimer.isRunning())
  713.         {
  714.             kbEscTimer.start(DELAY_ESCAPE);
  715.             return;
  716.         }
  717.  
  718.         /* key pressed within time limit */
  719.  
  720.         if (kbEscTimer.isRunning() && !kbEscTimer.isExpired())
  721.         {
  722.             kbEscTimer.stop();
  723.             if (code != 27)        /* simulate Alt-letter code */
  724.             {
  725.                 code = toupper(code);
  726.                 type = TALT;
  727.             }
  728.         }
  729.     }
  730.     else if (kbEscTimer.isExpired())    /* an Escape key timeout ? */
  731.     {
  732.         /* timeout condition: generate standard Esc code */
  733.  
  734.         kbEscTimer.stop();
  735.         code = 27;
  736.     }
  737.     else return;    /* nothing to do */
  738.  
  739.     int modifiers = kbReadShiftState();
  740.     if ((code = kbMapKey(code, type, modifiers)) != kbNoKey)
  741.     {
  742.         TEvent event;
  743.  
  744.         event.what = evKeyDown;
  745.         event.keyDown.keyCode = code;
  746.         event.keyDown.controlKeyState = modifiers;
  747.         TScreen::putEvent(event);
  748.     }
  749. }
  750.  
  751. /*
  752.  * MOUSE FUNCTIONS
  753.  */
  754.  
  755. /*
  756.  * This function inserts a mouse event in the event queue after adjusting the
  757.  * `event.mouse.buttons' field.
  758.  */
  759.  
  760. static void msPutEvent(TEvent &event, int buttons, int flags, int what)
  761. {
  762.     event.mouse.buttons = 0;
  763.     event.mouse.eventFlags = flags;
  764.     event.what = what;
  765.     if (TEventQueue::mouseReverse)    /* swap buttons ? */
  766.     {
  767.         if (buttons & mbLeftButton) event.mouse.buttons |=
  768.             mbRightButton;
  769.         if (buttons & mbRightButton) event.mouse.buttons |=
  770.             mbLeftButton;
  771.     }
  772.     else event.mouse.buttons = buttons;    /* no swapping */
  773.     TScreen::putEvent(event);
  774. }
  775.  
  776. /*
  777.  * Initializes the FreeBSD mouse.  The mouse is handled by the kernel.  We
  778.  * control it with ioctl(...) calls.
  779.  */
  780.  
  781. #ifdef ENABLE_FBSDM
  782. static void fbsdmInit()
  783. {
  784.     mouse_info_t mi;
  785.  
  786.     msAutoTimer.stop();
  787.     msDoubleTimer.stop();
  788.     msFlag = msOldButtons = 0;
  789.     msUseArrow = strstr(env, "noarrow") == NULL;
  790.     if (!msUseArrow) LOG("arrow pointer suppressed");
  791.     mi.operation = MOUSE_MODE;
  792.     mi.u.mode.signal = FBSDM_SIGNAL;
  793.     if (ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi) < 0)
  794.     {
  795.         LOG("unable to use the mouse");
  796.     }
  797.     mi.operation = MOUSE_GETINFO;
  798.     ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi);
  799.     msWhere.x = range(mi.u.data.x / 8, 0, TScreen::screenWidth - 1);
  800.     msWhere.y = range(mi.u.data.y / 16, 0, TScreen::screenHeight - 1);
  801. }
  802.  
  803. /*
  804.  * Closes the FreeBSD mouse.
  805.  */
  806.  
  807. static void fbsdmClose()
  808. {
  809.     mouse_info_t mi;
  810.  
  811.     mi.operation = MOUSE_MODE;
  812.     mi.u.mode.signal = 0;
  813.     ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi);
  814. }
  815.  
  816. /*
  817.  * Checks the status of every button and generates the related event.
  818.  */
  819.  
  820. static void fbsdmProcessButton(TEvent &event, int buttons, int mask)
  821. {
  822.     if (buttons & mask)    /* is button pressed ? */
  823.     {
  824.         msAutoTimer.start(DELAY_AUTOCLICK_FIRST);
  825.         if (msDoubleTimer.isRunning() && !msDoubleTimer.isExpired())
  826.         {
  827.             msDoubleTimer.stop();
  828.             msPutEvent(event, mask, meDoubleClick, evMouseDown);
  829.         }
  830.         else
  831.         {
  832.             msDoubleTimer.start(DELAY_DOUBLECLICK);
  833.             msPutEvent(event, mask, 0, evMouseDown);
  834.         }
  835.     }
  836.     else    /* button is released */
  837.     {
  838.         msAutoTimer.stop();
  839.         msPutEvent(event, mask, 0, evMouseUp);
  840.     }
  841. }
  842.  
  843. /*
  844.  * Handles events from the FreeBSD mouse driver.
  845.  */
  846.  
  847. static void fbsdmHandle()
  848. {
  849.     TEvent event;
  850.     mouse_info_t mi;
  851.  
  852.     mi.operation = MOUSE_GETINFO;
  853.     ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi);
  854.     event.mouse.controlKeyState = kbReadShiftState();
  855.     event.mouse.where.x = range(mi.u.data.x / 8, 0,
  856.         TScreen::screenWidth - 1);
  857.     event.mouse.where.y = range(mi.u.data.y / 16, 0,
  858.         TScreen::screenHeight - 1);
  859.  
  860.     /* convert button bits to TV standard */
  861.  
  862.     int buttons = 0;
  863.     if (mi.u.data.buttons & LEFT_BUTTON) buttons |= mbLeftButton;
  864.     if (mi.u.data.buttons & RIGHT_BUTTON) buttons |= mbRightButton;
  865.  
  866.     /* is mouse moved ? */
  867.  
  868.     if (event.mouse.where != msWhere)
  869.     {
  870.         msAutoTimer.stop();
  871.         msDoubleTimer.stop();
  872.         msPutEvent(event, buttons, meMouseMoved, evMouseMove);
  873.         msOldButtons = buttons;
  874.  
  875.         /* redraw the mouse in the new place */
  876.  
  877.         if (msUseArrow) msWhere = event.mouse.where;
  878.         else
  879.         {
  880.             TScreen::drawMouse(0);
  881.             msWhere = event.mouse.where;
  882.             TScreen::drawMouse(1);
  883.         }
  884.     }
  885.     if (buttons != msOldButtons)    /* is button state changed ? */
  886.     {
  887.         int changed = buttons ^ msOldButtons;
  888.         int i;
  889.         static int mask[] = { mbLeftButton, mbRightButton };
  890.  
  891.         /* check for pressed or released buttons */
  892.  
  893.         for (i = 0; i < 2; i++) if (changed & mask[i])
  894.         {
  895.             fbsdmProcessButton(event, buttons, mask[i]);
  896.         }
  897.         msOldButtons = buttons;
  898.     }
  899. }
  900. #endif
  901.  
  902. /*
  903.  * Opens the connection.
  904.  */
  905.  
  906. #ifdef HAVE_GPM_H
  907. static void gpmInit()
  908. {
  909.     msAutoTimer.stop();
  910.     msFd = -1;
  911.     msOldButtons = msWhere.x = msWhere.y = 0;
  912.     if (strstr(env, "nogpm") != NULL) LOG("gpm support disabled");
  913.     else
  914.     {
  915.         Gpm_Connect conn;
  916.  
  917.         conn.eventMask = ~0;    /* I want all events */
  918.         conn.defaultMask = 0;    /* no default treatment */
  919.         conn.maxMod = ~0;
  920.         conn.minMod = 0;
  921.         gpm_zerobased = 1;    /* coordinates start from zero */
  922.  
  923.         int testFd = Gpm_Open(&conn, 0);
  924.         /*
  925.          * The return value is either -1 or the file descriptor used
  926.          * to communicate with the server.  When run under xterm, a
  927.          * gpm client gets event through stdin, and the return value
  928.          * for Gpm_Open() will be -2.  This value is always available
  929.          * within gpm_fd.
  930.          */
  931.         if (testFd == -2 && mousemask(ALL_MOUSE_EVENTS |
  932.             REPORT_MOUSE_POSITION, NULL) != 0)
  933.         {
  934.             msFd = testFd;
  935.             LOG("gpm server " << Gpm_GetServerVersion(NULL));
  936.             LOG("gpm will send messages through ncurses");
  937.         }
  938.         else if (testFd >= 0)
  939.         {
  940.             msFd = testFd;
  941.             FD_SET(msFd, &fdSet);
  942.             LOG("gpm server " << Gpm_GetServerVersion(NULL));
  943.             LOG("gpm will send messages directly");
  944.         }
  945.         else LOG("no working gpm, running without mouse");
  946.     }
  947. }
  948.  
  949. /*
  950.  * Closes the connection.
  951.  */
  952.  
  953. static void gpmClose()
  954. {
  955.     if (msFd != -1)
  956.     {
  957.         Gpm_Close();
  958.         if (msFd == -2) mousemask(0, NULL);
  959.         else if (msFd >= 0) FD_CLR(msFd, &fdSet);
  960.         msFd = -1;
  961.     }
  962. }
  963.  
  964. /*
  965.  * Suspend connection, see Open and Close in `info gpm' for details.
  966.  */
  967.  
  968. static void gpmSuspend()
  969. {
  970.     if (msFd == -2) mousemask(0, NULL);
  971.     else if (msFd >= 0)
  972.     {
  973.         Gpm_Connect conn;
  974.  
  975.         /*
  976.          * Multiple opens are allowed, and a stack of Gpm_Connect
  977.          * structures is managed by the library.  You can, thus,
  978.          * re-open the connection in order to temporarily change the
  979.          * range of events you're interested in.  When you invoke an
  980.          * external program, for example, you should re-open the
  981.          * connection with eventMask zeroed, and defaultMask, minMod
  982.          * and maxMod all equal to ~0.
  983.          */
  984.         conn.eventMask = 0;
  985.         conn.defaultMask = ~0;
  986.         conn.maxMod = ~0;
  987.         conn.minMod = ~0;
  988.         gpm_zerobased = 0;
  989.         Gpm_Open(&conn, 0);
  990.     }
  991. }
  992.  
  993. /*
  994.  * Resume connection, see Open and Close in `info gpm' for details.
  995.  */
  996.  
  997. static void gpmResume()
  998. {
  999.     if (msFd == -2) mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION,
  1000.         NULL);
  1001.     else if (msFd >= 0)
  1002.     {
  1003.         /*
  1004.          * Pops the connection stack. It is used to restore the
  1005.          * previous situation after a change in the connection masks.
  1006.          * Closes the actual connection when the stack gets empty.  On
  1007.          * last close it returns 0, -1 otherwise.
  1008.          */
  1009.         Gpm_Close();
  1010.         gpm_zerobased = 1;
  1011.     }
  1012. }
  1013.  
  1014. /*
  1015.  * Handles mouse events.
  1016.  */
  1017.  
  1018. static void gpmHandle()
  1019. {
  1020.     Gpm_Event me;
  1021.     TEvent event;
  1022.  
  1023.     /*
  1024.      * Reads an event form gpm_fd.  It should be called only when the
  1025.      * gpm_fd descriptor is reported as readable by a select() system
  1026.      * call, or it will block until an event arrives (unless you put the
  1027.      * mouse file in non-blocking mode).  It returns 1 on success, -1 on
  1028.      * failure, and 0 after closing the connection.  Failure can happen if
  1029.      * a signal interrupted the read system call.  This function doesn't
  1030.      * work with xterm mouse reporting and is meant for internal use by
  1031.      * the library.
  1032.      */
  1033.     Gpm_GetEvent(&me);
  1034.     event.mouse.controlKeyState = kbReadShiftState();
  1035.     event.mouse.where.x = range(me.x, 0, TScreen::screenWidth - 1);
  1036.     event.mouse.where.y = range(me.y, 0, TScreen::screenHeight - 1);
  1037.  
  1038.     /* convert button bits to TV standard */
  1039.  
  1040.     int buttons = 0;
  1041.     if (me.buttons & GPM_B_LEFT) buttons |= mbLeftButton;
  1042.     if (me.buttons & GPM_B_RIGHT) buttons |= mbRightButton;
  1043.  
  1044.     /* is any button double-clicked ? */
  1045.  
  1046.     if (me.type & GPM_DOUBLE)
  1047.     {
  1048.         if (me.type & GPM_DOWN) return;
  1049.         if (me.type & GPM_UP)
  1050.         {
  1051.             msAutoTimer.stop();
  1052.             msPutEvent(event, buttons, meDoubleClick,
  1053.                 evMouseDown);
  1054.             msOldButtons &= ~buttons;
  1055.         }
  1056.     }
  1057.  
  1058.     /* is mouse moved ? */
  1059.  
  1060.     if (me.type & (GPM_DRAG | GPM_MOVE) && event.mouse.where != msWhere)
  1061.     {
  1062.         /*
  1063.          * Each bit set in buttons means the relative button is
  1064.          * down.
  1065.          */
  1066.         msAutoTimer.stop();
  1067.         msPutEvent(event, buttons, meMouseMoved, evMouseMove);
  1068.         msOldButtons = buttons;
  1069.  
  1070.         /* redraw the mouse in the new place */
  1071.  
  1072.         TScreen::drawMouse(0);
  1073.         msWhere = event.mouse.where;
  1074.         TScreen::drawMouse(1);
  1075.     }
  1076.     if (me.type & GPM_DOWN)    /* is any button pressed ? */
  1077.     {
  1078.         /*
  1079.          * Each bit in buttons reports the actual state of the
  1080.          * relative button.  We need to determine which button was
  1081.          * pressed.
  1082.          */
  1083.         msAutoTimer.start(DELAY_AUTOCLICK_FIRST);
  1084.         msPutEvent(event, buttons & ~msOldButtons, 0, evMouseDown);
  1085.         msOldButtons = buttons;
  1086.     }
  1087.     if (me.type & GPM_UP)    /* is any button released ? */
  1088.     {
  1089.         /*
  1090.          * Each bit set in buttons means the relative button was
  1091.          * released.
  1092.          */
  1093.         msAutoTimer.stop();
  1094.         msPutEvent(event, buttons, 0, evMouseUp);
  1095.         msOldButtons &= ~buttons;
  1096.     }
  1097. }
  1098. #endif
  1099.  
  1100. /*
  1101.  * Handles mouse events.
  1102.  *
  1103.  * This function was changed to fit the message handling of the ncurses mouse
  1104.  * support that differs from the gpm by the following:
  1105.  *
  1106.  * - sends mouse clicks, double clicks, etc;
  1107.  * - sends the message only once: we needn't lock messages;
  1108.  * - doesn't send mouse drag and mouse move messages (or may be I couldn't
  1109.  *   find the way to get them).
  1110.  */
  1111.  
  1112. #ifdef NCURSES_MOUSE_VERSION
  1113. static void msHandle()
  1114. {
  1115.     TEvent event;
  1116.     MEVENT me;
  1117. /*
  1118.        BUTTON1_PRESSED          mouse button 1 down
  1119.        BUTTON1_RELEASED         mouse button 1 up
  1120.        BUTTON1_CLICKED          mouse button 1 clicked
  1121.        BUTTON1_DOUBLE_CLICKED   mouse button 1 double clicked
  1122.        BUTTON1_TRIPLE_CLICKED   mouse button 1 triple clicked
  1123.        BUTTON2_PRESSED          mouse button 2 down
  1124.        BUTTON2_RELEASED         mouse button 2 up
  1125.        BUTTON2_CLICKED          mouse button 2 clicked
  1126.        BUTTON2_DOUBLE_CLICKED   mouse button 2 double clicked
  1127.        BUTTON2_TRIPLE_CLICKED   mouse button 2 triple clicked
  1128.        BUTTON3_PRESSED          mouse button 3 down
  1129.        BUTTON3_RELEASED         mouse button 3 up
  1130.        BUTTON3_CLICKED          mouse button 3 clicked
  1131.        BUTTON3_DOUBLE_CLICKED   mouse button 3 double clicked
  1132.        BUTTON3_TRIPLE_CLICKED   mouse button 3 triple clicked
  1133.        BUTTON4_PRESSED          mouse button 4 down
  1134.        BUTTON4_RELEASED         mouse button 4 up
  1135.        BUTTON4_CLICKED          mouse button 4 clicked
  1136.        BUTTON4_DOUBLE_CLICKED   mouse button 4 double clicked
  1137.        BUTTON4_TRIPLE_CLICKED   mouse button 4 triple clicked
  1138.        BUTTON_SHIFT             shift was down during button state change
  1139.        BUTTON_CTRL              control was down during button state change
  1140.        BUTTON_ALT               alt was down during button state change
  1141. */
  1142. #define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED)
  1143. #define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED)
  1144. #define BUTTON_DOUBLE_CLICKED (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED)
  1145. #define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED)
  1146. #define BUTTON1 (BUTTON1_PRESSED | BUTTON1_RELEASED | BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED)
  1147. #define BUTTON2 (BUTTON2_PRESSED | BUTTON2_RELEASED | BUTTON2_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON2_TRIPLE_CLICKED)
  1148. #define BUTTON3 (BUTTON3_PRESSED | BUTTON3_RELEASED | BUTTON3_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON3_TRIPLE_CLICKED)
  1149. #define BUTTON4 (BUTTON4_PRESSED | BUTTON4_RELEASED | BUTTON4_CLICKED | BUTTON4_DOUBLE_CLICKED | BUTTON4_TRIPLE_CLICKED)
  1150.  
  1151.     if (getmouse(&me) != OK) return;    /* exit if no event */
  1152.  
  1153.     event.mouse.controlKeyState = 0;
  1154.     if (me.bstate & BUTTON_SHIFT)
  1155.         event.mouse.controlKeyState |= kbLeftShift | kbRightShift;
  1156.     if (me.bstate & BUTTON_CTRL)
  1157.         event.mouse.controlKeyState |= kbLeftCtrl | kbRightCtrl;
  1158.     if (me.bstate & BUTTON_ALT)
  1159.         event.mouse.controlKeyState |= kbLeftAlt | kbRightAlt;
  1160.     me.x = (unsigned char) me.x;
  1161.     me.y = (unsigned char) me.y;
  1162.     event.mouse.where.x = range(me.x, 0, TScreen::screenWidth - 1);
  1163.     event.mouse.where.y = range(me.y, 0, TScreen::screenHeight - 1);
  1164.  
  1165.     /* convert button bits to TV standard */
  1166.  
  1167.     int buttons = mbLeftButton;
  1168.     if (me.bstate & BUTTON1) buttons = mbLeftButton;
  1169.     else if (me.bstate & BUTTON3) buttons = mbRightButton;
  1170.  
  1171.     if (me.bstate & BUTTON_CLICKED)        /* is any button clicked ? */
  1172.     {
  1173.         /* first generate a mouse down event */
  1174.  
  1175.         msPutEvent(event, buttons, 0, evMouseDown);
  1176.         msOldButtons = buttons;
  1177.  
  1178.         /* then generate a mouse up event */
  1179.  
  1180.         msAutoTimer.stop();
  1181.         msPutEvent(event, buttons, 0, evMouseUp);
  1182.         msOldButtons &= ~buttons;
  1183.     }
  1184.     if (me.bstate & BUTTON_DOUBLE_CLICKED)    /* any double-click ? */
  1185.     {
  1186.         msAutoTimer.stop();
  1187.         msPutEvent(event, buttons, meDoubleClick, evMouseDown);
  1188.         msOldButtons &= ~buttons;
  1189.     }
  1190.     if (event.mouse.where != msWhere)    /* is mouse moved ? */
  1191.     {
  1192.         if (me.bstate & BUTTON_PRESSED)
  1193.         {
  1194.             /* first generate a mouse move event */
  1195.  
  1196.             msPutEvent(event, buttons, meMouseMoved, evMouseMove);
  1197.             msWhere = event.mouse.where;
  1198.  
  1199.             /* then generate a mouse down event */
  1200.  
  1201.             msAutoTimer.start(DELAY_AUTOCLICK_FIRST);
  1202.             msPutEvent(event, buttons, 0, evMouseDown);
  1203.             msOldButtons = buttons;
  1204.         }
  1205.         if (me.bstate & BUTTON_RELEASED)
  1206.         {
  1207.             /* first generate a mouse move event */
  1208.  
  1209.             msPutEvent(event, buttons, meMouseMoved, evMouseMove);
  1210.             msWhere = event.mouse.where;
  1211.  
  1212.             /* then generate a mouse up event */
  1213.  
  1214.             msAutoTimer.stop();
  1215.             msPutEvent(event, buttons, 0, evMouseUp);
  1216.             msOldButtons &= ~buttons;
  1217.         }
  1218.     }
  1219.     else    /* mouse is not moved */
  1220.     {
  1221.         if (me.bstate & BUTTON_PRESSED)
  1222.         {
  1223.             /* generate a mouse down event */
  1224.  
  1225.             msAutoTimer.start(DELAY_AUTOCLICK_FIRST);
  1226.             msPutEvent(event, buttons, 0, evMouseDown);
  1227.             msOldButtons = buttons;
  1228.         }
  1229.         if (me.bstate & BUTTON_RELEASED)
  1230.         {
  1231.             /* generate a mouse up event */
  1232.  
  1233.             msAutoTimer.stop();
  1234.             msPutEvent(event, buttons, 0, evMouseUp);
  1235.             msOldButtons &= ~buttons;
  1236.         }
  1237.     }
  1238. }
  1239. #endif
  1240.  
  1241. /*
  1242.  * VCS FUNCTIONS
  1243.  */
  1244.  
  1245. /*
  1246.  * Initializes the vcs.
  1247.  */
  1248.  
  1249. #ifdef ENABLE_VCS
  1250. static void vcsInit()
  1251. {
  1252.     vcsFd = -1;
  1253.     vcsMap = NULL;            /* default is no character mapping */
  1254.     if (strstr(env, "novcs") != NULL) LOG("vcs support disabled");
  1255.     else
  1256.     {
  1257.         if (strstr(env, "cyrillic") != NULL)
  1258.         {
  1259.             /*
  1260.              * The cyrillic support was at half overwritten. I did
  1261.              * the following:
  1262.              *
  1263.              * - the translation table was changed to strictly
  1264.              *   convert koi8 to cp866;
  1265.              * - the following pseudographic symbols was changed
  1266.              *   to fit the koi8 table;
  1267.              * - the pcToAscii table was changed to fit the koi8
  1268.              *   table when "cyrillic" enabled.
  1269.              */
  1270.             LOG("using cyrillic character set");
  1271.             vcsMap = cyrillicTable;
  1272.             TMenuBox::frameChars = " \x9A\x84\xBF  \x80\x84\x99"
  1273.                 "  \xB3 \xB3  \x83\x84\xB4 ";
  1274.             memcpy(TFrame::frameChars,
  1275.                 "   \x80 \xB3\x9A\x83 \x99\x84\x81\xBF\xB4"
  1276.                 "\x82\x85   \x88 \xBA\x89\x87 \xBC\x8D\x8F"
  1277.                 "\xBB\xB6\x91 ", 33);
  1278.             TFrame::closeIcon = "[~\x04~]";
  1279.             TFrame::dragIcon = "~\x84\x99~";
  1280.             TIndicator::dragFrame = '\x8D';
  1281.             TIndicator::normalFrame = '\x84';
  1282.             THistory::icon = "\x9E~\x19~\x9D";
  1283.             TColorSelector::icon = '\x9B';
  1284.             TStatusLine::hintSeparator = "\xB3 ";
  1285.             TScrollChars vc = {30, 31, 177, 155, 178};
  1286.             memcpy(TScrollBar::vChars, vc, sizeof(vc));
  1287.             TScrollChars hc = {17, 16, 177, 155, 178};
  1288.             memcpy(TScrollBar::hChars, hc, sizeof(hc));
  1289.             TButton::shadows = "\x9D\x9B\x9F";
  1290.             TDirListBox::pathDir   = "\x80\x84\x82";
  1291.             TDirListBox::firstDir  =   "\x90\x82\x84";
  1292.             TDirListBox::middleDir =   " \x83\x84";
  1293.             TDirListBox::lastDir   =   " \x80\x84";
  1294.             TDirListBox::graphics = "\x80\x83\x84";
  1295.             TDeskTop::defaultBkgrnd = '\xB1';
  1296.             TListViewer::separatorChar = 179;
  1297.             TOutlineViewer::graphChars = "\x20\xB3\x83\x80\x84"
  1298.                 "\x84+\x84";
  1299.         }
  1300.         else if (strstr(env, "latin") != NULL)
  1301.         {
  1302.             LOG("using latin character set");
  1303.             vcsMap = latinTable;
  1304.         }
  1305.         else
  1306.         { 
  1307. #ifdef ENABLE_RUSSIAN_CHARSET
  1308.             LOG("wrong Russian character set");
  1309.             TFrame::closeIcon = "[~\x04~]";
  1310. #else
  1311.             LOG("using IBM PC character set");
  1312. #endif
  1313.         }
  1314.  
  1315.         /*
  1316.          * This approach was suggested by:
  1317.          * Martynas Kunigelis <algikun@santaka.sc-uni.ktu.lt>
  1318.          * Date: Mon, 20 Jan 1997 15:55:14 +0000 (EET)
  1319.          */
  1320.         FILE *statfile;
  1321.         char path[PATH_MAX];
  1322.  
  1323.         if ((statfile = fopen("/proc/self/stat", "r")) != NULL)
  1324.         {
  1325.             int dev;
  1326.  
  1327.             /* TTYs have 4 as major number */
  1328.             /* virtual consoles have minor numbers <= 63 */
  1329.  
  1330.             fscanf(statfile, "%*d %*s %*c %*d %*d %*d %d", &dev);
  1331.             if ((dev & 0xff00) == 0x0400 && (dev & 0xff) <= 63)
  1332.             {
  1333.                 LOG("virtual console detected");
  1334.                 sprintf(path, "/dev/vcsa%d", dev & 0xff);
  1335.                 if ((vcsFd = open(path, O_WRONLY)) < 0)
  1336.                 {
  1337.                     LOG("unable to open " << path <<
  1338.                         ", running in stdout mode");
  1339.                 }
  1340.             }
  1341.             fclose(statfile);
  1342.         }
  1343.     }
  1344. }
  1345.  
  1346. /*
  1347.  * Closes the vcs device.
  1348.  */
  1349.  
  1350. static void vcsClose()
  1351. {
  1352.     if (vcsFd >= 0) close(vcsFd);
  1353. }
  1354. #endif
  1355.  
  1356. /*
  1357.  * OTHER LOCAL FUNCTIONS
  1358.  */
  1359.  
  1360. /*
  1361.  * Select the best palette we can use.
  1362.  */
  1363.  
  1364. static void selectPalette()
  1365. {
  1366. #ifdef ENABLE_VCS
  1367.     if (vcsFd >= 0) TScreen::screenMode = TScreen::smCO80;
  1368.     else
  1369. #endif
  1370.     {
  1371.         if (has_colors()) TScreen::screenMode = TScreen::smCO80;
  1372.         else TScreen::screenMode = TScreen::smMono;
  1373.     }
  1374.     /*
  1375.      * This sets the standard attribute mapping to have 16 foreground
  1376.      * colors and 8 background colors.
  1377.      */
  1378.     if (TScreen::screenMode == TScreen::smCO80)
  1379.     {
  1380.         int back, fore, bold, i;
  1381.         /*
  1382.          * This loop allocates all the available color pair entries in
  1383.          * the following order:
  1384.          *
  1385.          * 7/0 7/1 7/2 ... ... 7/7
  1386.          * 6/0 6/1 6/2         6/7
  1387.          * 5/0 5/1 5/2         5/7
  1388.          * ...                 ...
  1389.          * ...                 ...
  1390.          * 0/0 0/1 0/2 ... ... 0/7
  1391.          * 
  1392.          * The first color pair must be 7/0 because it was hardcoded
  1393.          * to WHITE foreground on BLACK background in the ncurses
  1394.          * library.
  1395.          */
  1396.         i = 0;
  1397.         for (fore = COLORS - 1; fore >= 0; fore--)
  1398.         {
  1399.             for (back = 0; back < COLORS; back++)
  1400.             {
  1401.                 /*
  1402.                  * The first entry is hardcoded to WHITE on
  1403.                  * BLACK, so it does not allow redefinition.
  1404.                  */
  1405.                 if (i != 0) init_pair(i, fore, back);
  1406.                 i++; 
  1407.             }
  1408.         }
  1409.         /*
  1410.          * Now we map each possible physical color in a corresponding
  1411.          * attribute.
  1412.          */
  1413.         for (i = 0; i < 256; i++)
  1414.         {
  1415.             /*
  1416.              * The following table allows conversion from TV
  1417.              * colors indices to curses color indices.
  1418.              */
  1419.             static char map[] = {0, 4, 2, 6, 1, 5, 3, 7};
  1420.             /*
  1421.              * graphic card color    curses color
  1422.              * ---------------------------------
  1423.              *  0 black        0 black
  1424.              *  1 blue        1 red
  1425.              *  2 green        2 green
  1426.              *  3 cyan        3 brown
  1427.              *  4 red        4 blue
  1428.              *  5 magenta        5 magenta
  1429.              *  6 brown        6 cyan
  1430.              *  7 white        7 white 
  1431.              *  8 gray        0 black + A_BOLD
  1432.              *  9 light blue    1 red + A_BOLD
  1433.              * 10 light green    2 green + A_BOLD
  1434.              * 11 light cyan    3 brown + A_BOLD
  1435.              * 12 light red        4 blue + A_BOLD
  1436.              * 13 light magenta    5 magenta + A_BOLD
  1437.              * 14 yellow        6 cyan + A_BOLD
  1438.              * 15 light white    7 white + A_BOLD
  1439.              */
  1440.             /*
  1441.              * Extract color informations.
  1442.              *
  1443.              * - Bit 7 is set if blink is enabled.
  1444.              * - The background color is stored in the bits 6, 5
  1445.              *   and 4.
  1446.              * - Bit 3 is set if the foreground color is
  1447.              *   highlight.
  1448.              * - The foreground color is stored in the 3 lower
  1449.              *   bits (2, 1 and 0).
  1450.              */
  1451.             back = (i >> 4) & 0x07;
  1452.             bold = i & 0x08;
  1453.             fore = i & 0x07;
  1454.             /*
  1455.              * Now build the attribute value.
  1456.              */
  1457.             attributeMap[i] = COLOR_PAIR((7 - map[fore]) * 8 +
  1458.                 map[back]);
  1459.             if (bold != 0) attributeMap[i] |= A_BOLD;
  1460.         }
  1461.     }
  1462.     /*
  1463.      * This sets the standard attribute mapping for a monochrome output.
  1464.      */
  1465.     else if (TScreen::screenMode == TScreen::smMono)
  1466.     {
  1467.         attributeMap[0x07] = A_NORMAL;
  1468.         attributeMap[0x0f] = A_BOLD;
  1469.         attributeMap[0x70] = A_REVERSE;
  1470.     }
  1471. }
  1472.  
  1473. static void startcurses()
  1474. {
  1475.     initscr();        /* initialize the curses library */
  1476.     keypad(stdscr, TRUE);    /* enable keyboard mapping */
  1477.     cbreak();        /* do not wait for \n */
  1478.     noecho();        /* do not echo input */
  1479.     if (has_colors)    start_color();
  1480.     timeout(0);        /* set getch() in non-blocking mode */
  1481.     selectPalette();    /* select the more appropiate palette */
  1482.     TScreen::drawCursor(0);    /* hide the cursor */
  1483.     TScreen::drawMouse(1);    /* draw the mouse pointer */
  1484.  
  1485.     /* if possible we should use curses semigraphical characters */
  1486.  
  1487. #ifndef DISABLE_ACS
  1488.     if (strstr(env, "cyrillic") != NULL)
  1489.     {
  1490.         /*
  1491.          * The pcToAscii table was changed to fit the koi8 table that
  1492.          * differs from the IBM table.
  1493.          */
  1494.         pcToAscii[4] = ACS_DIAMOND;    /* 4 */
  1495.         pcToAscii[16] = ACS_RARROW;    /* 16 */
  1496.         pcToAscii[17] = ACS_LARROW;    /* 17 */
  1497.         pcToAscii[24] = ACS_UARROW;    /* 24 */
  1498.         pcToAscii[25] = ACS_DARROW;    /* 25 */
  1499.         pcToAscii[26] = ACS_RARROW;    /* 26 */
  1500.         pcToAscii[27] = ACS_LARROW;    /* 27 */
  1501.         pcToAscii[28] = ACS_LLCORNER;    /* 28 */
  1502.         pcToAscii[30] = ACS_UARROW;    /* 30 */
  1503.         pcToAscii[31] = ACS_DARROW;    /* 31 */
  1504.     #ifdef ACS_STERLING
  1505.         pcToAscii[166] = ACS_STERLING;    /* 156 */
  1506.     #endif
  1507.         pcToAscii[176] = ACS_BOARD;    /* 176 */
  1508.         pcToAscii[177] = ACS_CKBOARD;    /* 177 */
  1509.         pcToAscii[178] = ACS_CKBOARD;    /* 178 */
  1510.         pcToAscii[179] = ACS_VLINE;    /* 179 */
  1511.         pcToAscii[180] = ACS_RTEE;    /* 180 */
  1512.         pcToAscii[181] = ACS_RTEE;    /* 181 */
  1513.         pcToAscii[182] = ACS_RTEE;    /* 182 */
  1514.         pcToAscii[183] = ACS_URCORNER;    /* 183 */
  1515.         pcToAscii[184] = ACS_URCORNER;    /* 184 */
  1516.         pcToAscii[185] = ACS_RTEE;    /* 185 */
  1517.         pcToAscii[186] = ACS_VLINE;    /* 186 */
  1518.         pcToAscii[187] = ACS_URCORNER;    /* 187 */
  1519.         pcToAscii[188] = ACS_LRCORNER;    /* 188 */
  1520.         pcToAscii[189] = ACS_LRCORNER;    /* 189 */
  1521.         pcToAscii[190] = ACS_LRCORNER;    /* 190 */
  1522.         pcToAscii[191] = ACS_URCORNER;    /* 191 */
  1523.         pcToAscii[128] = ACS_LLCORNER;    /* 192 */
  1524.         pcToAscii[129] = ACS_BTEE;    /* 193 */
  1525.         pcToAscii[130] = ACS_TTEE;    /* 194 */
  1526.         pcToAscii[131] = ACS_LTEE;    /* 195 */
  1527.         pcToAscii[132] = ACS_HLINE;    /* 196 */
  1528.         pcToAscii[133] = ACS_PLUS;    /* 197 */
  1529.         pcToAscii[134] = ACS_LTEE;    /* 198 */
  1530.         pcToAscii[135] = ACS_LTEE;    /* 199 */
  1531.         pcToAscii[136] = ACS_LLCORNER;    /* 200 */
  1532.         pcToAscii[137] = ACS_ULCORNER;    /* 201 */
  1533.         pcToAscii[138] = ACS_BTEE;    /* 202 */
  1534.         pcToAscii[139] = ACS_TTEE;    /* 203 */
  1535.         pcToAscii[140] = ACS_LTEE;    /* 204 */
  1536.         pcToAscii[141] = ACS_HLINE;    /* 205 */
  1537.         pcToAscii[142] = ACS_PLUS;    /* 206 */
  1538.         pcToAscii[143] = ACS_BTEE;    /* 207 */
  1539.         pcToAscii[144] = ACS_BTEE;    /* 208 */
  1540.         pcToAscii[145] = ACS_TTEE;    /* 209 */
  1541.         pcToAscii[146] = ACS_TTEE;    /* 210 */
  1542.         pcToAscii[147] = ACS_LLCORNER;    /* 211 */
  1543.         pcToAscii[148] = ACS_LLCORNER;    /* 212 */
  1544.         pcToAscii[149] = ACS_ULCORNER;    /* 213 */
  1545.         pcToAscii[150] = ACS_ULCORNER;    /* 214 */
  1546.         pcToAscii[151] = ACS_PLUS;    /* 215 */
  1547.         pcToAscii[152] = ACS_PLUS;    /* 216 */
  1548.         pcToAscii[153] = ACS_LRCORNER;    /* 217 */
  1549.         pcToAscii[154] = ACS_ULCORNER;    /* 218 */
  1550.         pcToAscii[155] = ACS_BLOCK;    /* 219 */
  1551.         pcToAscii[156] = ACS_BLOCK;    /* 220 */
  1552.         pcToAscii[157] = ACS_BLOCK;    /* 221 */
  1553.         pcToAscii[158] = ACS_BLOCK;    /* 222 */
  1554.         pcToAscii[159] = ACS_BLOCK;    /* 223 */
  1555.     #ifdef ACS_PI
  1556.         pcToAscii[164] = ACS_PI;    /* 227 */
  1557.     #endif
  1558.         pcToAscii[161] = ACS_PLMINUS;    /* 241 */
  1559.     #ifdef ACS_GEQUAL
  1560.         pcToAscii[162] = ACS_GEQUAL;    /* 242 */
  1561.     #endif
  1562.     #ifdef ACS_LEQUAL
  1563.         pcToAscii[163] = ACS_LEQUAL;    /* 243 */
  1564.     #endif
  1565.         pcToAscii[167] = ACS_DEGREE;    /* 248 */
  1566.         pcToAscii[255] = ACS_BULLET;    /* 254 */
  1567.     }
  1568.     else
  1569.     {
  1570.         pcToAscii[4] = ACS_DIAMOND;    /* 4 */
  1571.         pcToAscii[24] = ACS_UARROW;    /* 24 */
  1572.         pcToAscii[26] = ACS_RARROW;    /* 26 */
  1573.         pcToAscii[27] = ACS_LARROW;    /* 27 */
  1574.         pcToAscii[28] = ACS_LLCORNER;    /* 28 */
  1575.         /*
  1576.          * And here is the one more plug that was written for the
  1577.          * backward compatibility.
  1578.          */
  1579. #ifdef ENABLE_RUSSIAN_CHARSET
  1580.         pcToAscii[176] = ACS_CKBOARD;    /* 176 */
  1581. #else
  1582.         pcToAscii[16] = ACS_RARROW;    /* 16 */
  1583.         pcToAscii[17] = ACS_LARROW;    /* 17 */
  1584.         pcToAscii[25] = ACS_DARROW;    /* 25 */
  1585.         pcToAscii[30] = ACS_UARROW;    /* 30 */
  1586.         pcToAscii[31] = ACS_DARROW;    /* 31 */
  1587.     #ifdef ACS_STERLING
  1588.         pcToAscii[156] = ACS_STERLING;    /* 156 */
  1589.     #endif
  1590.         pcToAscii[169] = ACS_ULCORNER;    /* 169 */
  1591.         pcToAscii[170] = ACS_URCORNER;    /* 170 */
  1592.         pcToAscii[174] = ACS_LARROW;    /* 174 */
  1593.         pcToAscii[175] = ACS_RARROW;    /* 175 */
  1594.         pcToAscii[176] = ACS_BOARD;    /* 176 */
  1595. #endif
  1596.         pcToAscii[177] = ACS_CKBOARD;    /* 177 */
  1597.         pcToAscii[178] = ACS_CKBOARD;    /* 178 */
  1598.         pcToAscii[179] = ACS_VLINE;    /* 179 */
  1599.         pcToAscii[180] = ACS_RTEE;    /* 180 */
  1600.         pcToAscii[181] = ACS_RTEE;    /* 181 */
  1601.         pcToAscii[182] = ACS_RTEE;    /* 182 */
  1602.         pcToAscii[183] = ACS_URCORNER;    /* 183 */
  1603.         pcToAscii[184] = ACS_URCORNER;    /* 184 */
  1604.         pcToAscii[185] = ACS_RTEE;    /* 185 */
  1605.         pcToAscii[186] = ACS_VLINE;    /* 186 */
  1606.         pcToAscii[187] = ACS_URCORNER;    /* 187 */
  1607.         pcToAscii[188] = ACS_LRCORNER;    /* 188 */
  1608.         pcToAscii[189] = ACS_LRCORNER;    /* 189 */
  1609.         pcToAscii[190] = ACS_LRCORNER;    /* 190 */
  1610.         pcToAscii[191] = ACS_URCORNER;    /* 191 */
  1611.         pcToAscii[192] = ACS_LLCORNER;    /* 192 */
  1612.         pcToAscii[193] = ACS_BTEE;    /* 193 */
  1613.         pcToAscii[194] = ACS_TTEE;    /* 194 */
  1614.         pcToAscii[195] = ACS_LTEE;    /* 195 */
  1615.         pcToAscii[196] = ACS_HLINE;    /* 196 */
  1616.         pcToAscii[197] = ACS_PLUS;    /* 197 */
  1617.         pcToAscii[198] = ACS_LTEE;    /* 198 */
  1618.         pcToAscii[199] = ACS_LTEE;    /* 199 */
  1619.         pcToAscii[200] = ACS_LLCORNER;    /* 200 */
  1620.         pcToAscii[201] = ACS_ULCORNER;    /* 201 */
  1621.         pcToAscii[202] = ACS_BTEE;    /* 202 */
  1622.         pcToAscii[203] = ACS_TTEE;    /* 203 */
  1623.         pcToAscii[204] = ACS_LTEE;    /* 204 */
  1624.         pcToAscii[205] = ACS_HLINE;    /* 205 */
  1625.         pcToAscii[206] = ACS_PLUS;    /* 206 */
  1626.         pcToAscii[207] = ACS_BTEE;    /* 207 */
  1627.         pcToAscii[208] = ACS_BTEE;    /* 208 */
  1628.         pcToAscii[209] = ACS_TTEE;    /* 209 */
  1629.         pcToAscii[210] = ACS_TTEE;    /* 210 */
  1630.         pcToAscii[211] = ACS_LLCORNER;    /* 211 */
  1631.         pcToAscii[212] = ACS_LLCORNER;    /* 212 */
  1632.         pcToAscii[213] = ACS_ULCORNER;    /* 213 */
  1633.         pcToAscii[214] = ACS_ULCORNER;    /* 214 */
  1634.         pcToAscii[215] = ACS_PLUS;    /* 215 */
  1635.         pcToAscii[216] = ACS_PLUS;    /* 216 */
  1636.         pcToAscii[217] = ACS_LRCORNER;    /* 217 */
  1637.         pcToAscii[218] = ACS_ULCORNER;    /* 218 */
  1638.         pcToAscii[219] = ACS_BLOCK;    /* 219 */
  1639.         pcToAscii[220] = ACS_BLOCK;    /* 220 */
  1640.         pcToAscii[221] = ACS_BLOCK;    /* 221 */
  1641.         pcToAscii[222] = ACS_BLOCK;    /* 222 */
  1642.         pcToAscii[223] = ACS_BLOCK;    /* 223 */
  1643.     #ifdef ACS_PI
  1644.         pcToAscii[245] = ACS_PI;    /* 227 */
  1645.     #endif
  1646.         pcToAscii[241] = ACS_PLMINUS;    /* 241 */
  1647.     #ifdef ACS_GEQUAL
  1648.         pcToAscii[242] = ACS_GEQUAL;    /* 242 */
  1649.     #endif
  1650.     #ifdef ACS_LEQUAL
  1651.         pcToAscii[243] = ACS_LEQUAL;    /* 243 */
  1652.     #endif
  1653.         pcToAscii[248] = ACS_DEGREE;    /* 248 */
  1654.         pcToAscii[254] = ACS_BULLET;    /* 254 */
  1655.     }
  1656. #endif
  1657. }
  1658.  
  1659. static void stopcurses()
  1660. {
  1661.     /*
  1662.      * The erase and werase routines copy blanks to every position in the
  1663.      * window, clearing the screen.  The clear and wclear routines are
  1664.      * like erase and werase, but they also call clearok, so that the
  1665.      * screen is cleared completely on the next call to wrefresh for that
  1666.      * window and repainted from scratch.
  1667.      */
  1668.     clear();        /* blank the screen */
  1669.     refresh();        /* this is necessary */
  1670.     keypad(stdscr, FALSE);    /* disable keyboard mapping */
  1671.     nocbreak();        /* wait for \n */
  1672.     echo();            /* echo input */
  1673.     endwin();        /* close the curses library */
  1674. }
  1675.  
  1676. /*
  1677.  * Show a warning message.
  1678.  */
  1679.  
  1680. static int confirmExit()
  1681. {
  1682.     /* we need the buffer address */
  1683.  
  1684.     class MyBuffer: public TDrawBuffer
  1685.     {
  1686.     public:
  1687.         ushort *getBufAddr() { return data; }
  1688.     };
  1689.     MyBuffer b;
  1690.     static char msg[] = "Warning: are you sure you want to quit ?";
  1691.  
  1692.     b.moveChar(0, ' ', 0x4f, TScreen::screenWidth);
  1693.     b.moveStr(max((TScreen::screenWidth - (int) (sizeof(msg) - 1)) / 2,
  1694.         0), msg, 0x4f);
  1695.     TScreen::writeRow(0, b.getBufAddr(), TScreen::screenWidth);
  1696.  
  1697.     timeout(-1);    /* set getch() in blocking mode */
  1698.     int key = getch();
  1699.     timeout(0);    /* set getch() in non-blocking mode */
  1700.     return toupper(key) == 'Y';
  1701. }
  1702.  
  1703. /*
  1704.  * General signal handler.
  1705.  */
  1706.  
  1707. static void sigHandler(int signo)
  1708. {
  1709.     struct sigaction dfl_handler;
  1710.  
  1711.     sigemptyset(&dfl_handler.sa_mask);
  1712.     dfl_handler.sa_flags = SA_RESTART;
  1713.  
  1714.     switch (signo)
  1715.     {
  1716. #ifdef ENABLE_FBSDM
  1717.     case FBSDM_SIGNAL:
  1718.         msFlag++;
  1719.         break;
  1720. #endif
  1721.     case SIGALRM:
  1722.         /*
  1723.          * called every DELAY_SIGALRM ms
  1724.          */
  1725.         currentTime += DELAY_SIGALRM;
  1726.         break;
  1727.     case SIGCONT:
  1728.         /*
  1729.          * called when the user restart the process after a ctrl-z
  1730.          */
  1731.         LOG("continuing process");
  1732.         TScreen::resume();
  1733.  
  1734.         /* re-enable SIGTSTP */
  1735.  
  1736.         dfl_handler.sa_handler = sigHandler;
  1737.         sigaction(SIGTSTP, &dfl_handler, NULL);
  1738.         break;
  1739.     case SIGINT:
  1740.     case SIGQUIT:
  1741.         /*
  1742.          * These signals are now trapped.
  1743.          * Date: Wed, 12 Feb 1997 10:45:55 +0100 (MET)
  1744.          *
  1745.          * Ignore SIGINT and SIGQUIT to avoid recursive calls.
  1746.          */
  1747.         dfl_handler.sa_handler = SIG_IGN;
  1748.         sigaction(SIGINT, &dfl_handler, NULL);
  1749.         sigaction(SIGQUIT, &dfl_handler, NULL);
  1750.  
  1751.         /* ask the user what to do */
  1752.  
  1753.         if (confirmExit()) exit(EXIT_FAILURE);
  1754.         doRepaint++;
  1755.  
  1756.         /* re-enable SIGINT and SIGQUIT */
  1757.  
  1758.         dfl_handler.sa_handler = sigHandler;
  1759.         sigaction(SIGINT, &dfl_handler, NULL);
  1760.         sigaction(SIGQUIT, &dfl_handler, NULL);
  1761.         break;
  1762.     case SIGTSTP:
  1763.         /*
  1764.          * called when the user presses ctrl-z
  1765.          */
  1766.         TScreen::suspend();
  1767.         LOG("process stopped");
  1768.  
  1769.         /* use the default handler for SIGTSTP */
  1770.  
  1771.         dfl_handler.sa_handler = SIG_DFL;
  1772.         sigaction(SIGTSTP, &dfl_handler, NULL);
  1773.         raise(SIGTSTP);        /* stop the process */
  1774.         break;
  1775.     case SIGWINCH:
  1776.         doResize++;
  1777.     }
  1778. }
  1779.  
  1780. /*
  1781.  * CLASS FUNCTIONS
  1782.  */
  1783.  
  1784. /*
  1785.  * TScreen constructor.
  1786.  */
  1787.  
  1788. TScreen::TScreen()
  1789. {
  1790.     char *p = getenv("TVLOG");
  1791.     if (p != NULL && *p != '\0')
  1792.     {
  1793.         xlog.open(p);
  1794.         LOG("using environment variable TVLOG=" << p);
  1795.     }
  1796.     else xlog.open("/dev/null");
  1797.     env[0] = '\0';
  1798.     if ((p = getenv("TVOPT")) != NULL)
  1799.     {
  1800.         LOG("using environment variable TVOPT=" << p);
  1801.         for (char *d = env; *p != '\0'; p++) *d++ = tolower(*p);
  1802.     }
  1803.  
  1804.     /* acquire screen size */
  1805.  
  1806.     winsize win;
  1807.     ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
  1808.     if (win.ws_col > 0 && win.ws_row > 0)
  1809.     {
  1810.         screenWidth = range(win.ws_col, 4, maxViewWidth);
  1811.         screenHeight = range(win.ws_row, 4, 80);
  1812.     }
  1813.     else
  1814.     {
  1815.         LOG("unable to detect screen size, using 80x25");
  1816.         screenWidth = 80;
  1817.         screenHeight = 25;
  1818.     }
  1819. #ifdef __FreeBSD__
  1820.     /*
  1821.      * Kludge: until we find a right way to fix the "last-line" display
  1822.      * problem, this is a solution.
  1823.      */
  1824.     screenHeight--;
  1825. #endif
  1826.     LOG("screen size is " << (int) screenWidth << "x" <<
  1827.         (int) screenHeight);
  1828.     screenBuffer = new ushort[screenWidth * screenHeight];
  1829.  
  1830.     /* internal stuff */
  1831.  
  1832.     curX = curY = 0;
  1833.     currentTime = doRepaint = doResize = evLength = 0;
  1834.     evIn = evOut = &evQueue[0];
  1835.     kbEscTimer.stop();
  1836.     msAutoTimer.stop();
  1837.     msOldButtons = msWhere.x = msWhere.y = 0;
  1838.     wakeupTimer.start(DELAY_WAKEUP);
  1839.  
  1840.     /* setup file descriptors */
  1841.  
  1842.     FD_ZERO(&fdSet);
  1843.     FD_SET(STDIN_FILENO, &fdSet);
  1844.  
  1845. #ifdef ENABLE_FBSDM
  1846.     fbsdmInit();
  1847. #endif
  1848. #ifdef ENABLE_VCS
  1849.     vcsInit();
  1850. #endif
  1851.     /*
  1852.      * We have to call startcurses() before the gpmInit(), otherwise we
  1853.      * shall not have the mouse (see the curs_mouse manual page for more
  1854.      * details).
  1855.      */
  1856.     startcurses();        /* curses stuff */
  1857. #ifdef HAVE_GPM_H
  1858.     gpmInit();
  1859. #endif
  1860.     /* catch useful signals */
  1861.  
  1862.     struct sigaction dfl_handler;
  1863.  
  1864.     dfl_handler.sa_handler = sigHandler;
  1865.     sigemptyset(&dfl_handler.sa_mask);
  1866.     dfl_handler.sa_flags = SA_RESTART;
  1867.  
  1868. #ifdef ENABLE_FBSDM
  1869.     sigaction(FBSDM_SIGNAL, &dfl_handler, NULL);
  1870. #endif
  1871.     sigaction(SIGALRM, &dfl_handler, NULL);
  1872.     sigaction(SIGCONT, &dfl_handler, NULL);
  1873.     sigaction(SIGINT, &dfl_handler, NULL);
  1874.     sigaction(SIGQUIT, &dfl_handler, NULL);
  1875.     sigaction(SIGTSTP, &dfl_handler, NULL);
  1876.     sigaction(SIGWINCH, &dfl_handler, NULL);
  1877.  
  1878.     /* generates a SIGALRM signal every DELAY_SIGALRM ms */
  1879.  
  1880.     struct itimerval timer;
  1881.     timer.it_interval.tv_usec = timer.it_value.tv_usec =
  1882.         DELAY_SIGALRM * 1000;
  1883.     timer.it_interval.tv_sec = timer.it_value.tv_sec = 0;
  1884.     setitimer(ITIMER_REAL, &timer, NULL);
  1885. }
  1886.  
  1887. /*
  1888.  * TScreen destructor.
  1889.  */
  1890.  
  1891. TScreen::~TScreen()
  1892. {
  1893.     drawMouse(0);
  1894. #ifdef HAVE_GPM_H
  1895.     gpmClose();
  1896. #endif
  1897.     stopcurses();
  1898. #ifdef ENABLE_VCS
  1899.     vcsClose();
  1900. #endif
  1901. #ifdef ENABLE_FBSDM
  1902.     fbsdmClose();
  1903. #endif
  1904.     delete[] screenBuffer;
  1905.     LOG("terminated");
  1906. }
  1907.  
  1908. void TScreen::resume()
  1909. {
  1910.     startcurses();
  1911. #ifdef HAVE_GPM_H
  1912.     gpmResume();
  1913. #endif
  1914.     doRepaint++;
  1915. }
  1916.  
  1917. void TScreen::suspend()
  1918. {
  1919. #ifdef HAVE_GPM_H
  1920.     gpmSuspend();
  1921. #endif
  1922.     stopcurses();
  1923. }
  1924.  
  1925. /*
  1926.  * Gets an event from the queue.
  1927.  */
  1928.  
  1929. void TScreen::getEvent(TEvent &event)
  1930. {
  1931.     event.what = evNothing;
  1932.     if (doRepaint > 0)
  1933.     {
  1934.         doRepaint = 0;
  1935.         event.message.command = cmSysRepaint;
  1936.         event.what = evCommand;
  1937.     }
  1938.     else if (doResize > 0)
  1939.     {
  1940.         /*
  1941.          * wresize(...) generates a segmentation fault.  Any idea ?
  1942.          *
  1943.          * Added the gpmSuspend and gpmResume function calls,
  1944.          * otherwise we loose mouse.
  1945.          */
  1946. #ifdef HAVE_GPM_H
  1947.         gpmSuspend();
  1948. #endif
  1949.         clear();    /* blank the screen */
  1950.         refresh();    /* this is necessary */
  1951.         stopcurses();
  1952.         startcurses();
  1953. #ifdef HAVE_GPM_H
  1954.         gpmResume();
  1955. #endif
  1956.         doResize = 0;
  1957.         winsize win;
  1958.         ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
  1959.         if (win.ws_col > 0 && win.ws_row > 0)
  1960.         {
  1961.             screenWidth = range(win.ws_col, 4, maxViewWidth);
  1962.             screenHeight = range(win.ws_row, 4, 80);
  1963.             delete[] screenBuffer;
  1964.             screenBuffer = new ushort[screenWidth * screenHeight];
  1965.             LOG("screen resized to " << (int) screenWidth << "x"
  1966.                 << (int) screenHeight);
  1967.         }
  1968.         event.message.command = cmSysResize;
  1969.         event.what = evCommand;
  1970.     }
  1971.     else if (evLength > 0)    /* handles pending events */
  1972.     {
  1973.         evLength--;
  1974.         event = *evOut;
  1975.         if (++evOut >= &evQueue[eventQSize]) evOut = &evQueue[0];
  1976.     }
  1977. #ifdef ENABLE_FBSDM
  1978.     else if (msFlag > 0)
  1979.     {
  1980.         msFlag--;
  1981.         fbsdmHandle();
  1982.     }
  1983. #endif
  1984.     else if (msAutoTimer.isExpired())
  1985.     {
  1986.         /*
  1987.          * Now evMouseAuto works well.
  1988.          * Date: Tue, 28 Jan 1997 19:35:31 +0100 (MET)
  1989.          */
  1990.         msAutoTimer.start(DELAY_AUTOCLICK_NEXT);
  1991.         event.mouse.buttons = msOldButtons;
  1992.         event.mouse.where = msWhere;
  1993.         event.what = evMouseAuto;
  1994.     }
  1995.     else if (wakeupTimer.isExpired())
  1996.     {
  1997.         wakeupTimer.start(DELAY_WAKEUP);
  1998.         event.message.command = cmSysWakeup;
  1999.         event.what = evCommand;
  2000.     }
  2001.     else
  2002.     {
  2003.         fd_set ready = fdSet;
  2004.         int kbReady = 0;
  2005.  
  2006.         /*
  2007.          * suspend until there is a signal or some data in file
  2008.          * descriptors
  2009.          */
  2010.         if (select(FD_SETSIZE, &ready, NULL, NULL, NULL) > 0)
  2011.         {
  2012.             kbReady = FD_ISSET(STDIN_FILENO, &ready);
  2013. #ifdef HAVE_GPM_H
  2014.             if (msFd >= 0 && FD_ISSET(msFd, &ready)) gpmHandle();
  2015.         }
  2016.         else if (msFd >= 0 && !gpm_flag)
  2017.         {
  2018.             LOG("lost connection to gpm server");
  2019.             drawMouse(0);
  2020.             gpmClose();
  2021. #endif
  2022.         }
  2023.         if (kbReady || kbEscTimer.isRunning()) kbHandle();
  2024.     }
  2025. }
  2026.  
  2027. /*
  2028.  * Generates a beep.
  2029.  */
  2030.  
  2031. void TScreen::makeBeep()
  2032. {
  2033. #ifdef ENABLE_VCS
  2034.     /*
  2035.      * We can't call refresh() when using VCS, otherwise it will clear the
  2036.      * screen.
  2037.      */
  2038.     if (vcsFd >= 0)
  2039.     {
  2040.         /*
  2041.          * high word = clock ticks
  2042.          * low word = counter value (1193180 / frequency)
  2043.          */
  2044.         ioctl(STDIN_FILENO, KDMKTONE, 0x005004a9);
  2045.     }
  2046.     else
  2047. #endif
  2048.     {
  2049.         beep();
  2050.         refresh();
  2051.     }
  2052. }
  2053.  
  2054. /*
  2055.  * Puts an event in the queue.  If the queue is full the event will be
  2056.  * discarded.
  2057.  */
  2058.  
  2059. void TScreen::putEvent(TEvent &event)
  2060. {
  2061.     if (evLength < eventQSize)
  2062.     {
  2063.         evLength++;
  2064.         *evIn = event;
  2065.         if (++evIn >= &evQueue[eventQSize]) evIn = &evQueue[0];
  2066.     }
  2067. }
  2068.  
  2069. /*
  2070.  * Hides or shows the cursor.
  2071.  */
  2072.  
  2073. void TScreen::drawCursor(int show)
  2074. {
  2075.     /*
  2076.      * This patch makes tvision port for Linux happy whith ncurses-4.1 and
  2077.      * adds more graceful cursor management.
  2078.      *
  2079.      * From: Ruslan V. Brushkoff <ruslan@Baby.TM.Odessa.UA>
  2080.      * Date: Wed, 18 Jun 1997 07:32:15 +0300 (EET DST)
  2081.      */
  2082. #ifdef NCURSES_VERSION
  2083. #ifdef ENABLE_VCS
  2084.     if (vcsFd < 0)
  2085.     {
  2086. #endif
  2087.         if (show) curs_set(1);    /* cursor normal */
  2088.         else curs_set(0);    /* cursor invisible */
  2089. #ifdef ENABLE_VCS
  2090.     }
  2091.     else if (!show) moveCursor(screenWidth - 1, screenHeight - 1);
  2092. #endif
  2093. #else
  2094.     if (!show) moveCursor(screenWidth - 1, screenHeight - 1);
  2095. #endif
  2096. }
  2097.  
  2098. /*
  2099.  * Hides or shows the mouse pointer.
  2100.  */
  2101.  
  2102. void TScreen::drawMouse(int show)
  2103. {
  2104. #if defined(ENABLE_FBSDM) || defined(HAVE_GPM_H)
  2105. #ifdef ENABLE_FBSDM
  2106.     if (msUseArrow)
  2107.     {
  2108.         mouse_info_t mi;
  2109.  
  2110.         mi.operation = MOUSE_HIDE;
  2111.         ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi);
  2112.         if (show)
  2113.         {
  2114.             mi.operation = MOUSE_SHOW;
  2115.             ioctl(STDOUT_FILENO, CONS_MOUSECTL, &mi);
  2116.         }
  2117.     }
  2118.     else
  2119. #endif
  2120.     {
  2121. #ifdef HAVE_GPM_H
  2122.         if (msFd < 0) return;
  2123. #endif
  2124.         int addr = screenWidth * msWhere.y + msWhere.x;
  2125.         ushort cell = screenBuffer[addr];
  2126. #ifdef ENABLE_VCS
  2127.         if (vcsFd >= 0)        /* use vcs */
  2128.         {
  2129.             if (show) cell ^= 0x7f00;
  2130.  
  2131.             /* map IBM PC character set to another code page ? */
  2132.  
  2133.             if (vcsMap != NULL)
  2134.             {
  2135.                 if ((cell & 0x00ff) >= 0x80)
  2136.                     cell = (cell & 0xff00) |
  2137.                     vcsMap[(cell & 0x00ff) - 0x80];
  2138.             }
  2139.             lseek(vcsFd, addr * sizeof(ushort) + 4, SEEK_SET);
  2140.             write(vcsFd, &cell, sizeof(ushort));
  2141.         }
  2142.         else            /* standard out */
  2143. #endif
  2144.         {
  2145.             int code = cell & 0xff;
  2146.             int color = (cell & 0xff00) >> 8;
  2147.  
  2148.             if (screenMode == smCO80)
  2149.             {
  2150.                 /* invert the colors */
  2151.  
  2152.                 if (show) color ^= 0x7f;
  2153.             }
  2154.             else if (screenMode == smMono)
  2155.             {
  2156.                 /* rotate the colors */
  2157.  
  2158.                 if (show) switch (color)
  2159.                 {
  2160.                 case 0x07: color = 0x70; break;
  2161.                 case 0x0f: color = 0x70; break;
  2162.                 case 0x70: color = 0x0f;
  2163.                 }
  2164.             }
  2165.             move(msWhere.y, msWhere.x);
  2166.             attrset(attributeMap[color]);
  2167.             addch(pcToAscii[code]);
  2168.             move(curY, curX);
  2169.             refresh();    /* this is necessary */
  2170.         }
  2171.     }
  2172. #endif
  2173. }
  2174.  
  2175. /*
  2176.  * Moves the cursor to another place.
  2177.  */
  2178.  
  2179. void TScreen::moveCursor(int x, int y)
  2180. {
  2181. #ifdef ENABLE_VCS
  2182.     if (vcsFd >= 0)        /* use vcs */
  2183.     {
  2184.         unsigned char where[2] = {x, y};
  2185.  
  2186.         lseek(vcsFd, 2, SEEK_SET);
  2187.         write(vcsFd, where, sizeof(where));
  2188.     }
  2189.     else            /* standard out */
  2190. #endif
  2191.     {
  2192.         move(y, x);
  2193.         refresh();    /* this is necessary */
  2194.     }
  2195.     curX = x;
  2196.     curY = y;
  2197. }
  2198.  
  2199. /*
  2200.  * Draws a line of text on the screen.
  2201.  */
  2202.  
  2203. void TScreen::writeRow(int dst, ushort *src, int len)
  2204. {
  2205. #ifdef ENABLE_VCS
  2206.     if (vcsFd >= 0)        /* use vcs */
  2207.     {
  2208.         lseek(vcsFd, dst * sizeof(ushort) + 4, SEEK_SET);
  2209.  
  2210.         /* map IBM PC character set to another code page ? */
  2211.  
  2212.         if (vcsMap != NULL)
  2213.         {
  2214.             int i = len;
  2215.             ushort buf[maxViewWidth];
  2216.             ushort *from = src;
  2217.             ushort *to = buf;
  2218.  
  2219.             while (i-- > 0)
  2220.             {
  2221.                 /* extract character and attribute pair */
  2222.  
  2223.                 ushort pair = *from++;
  2224.  
  2225.                 /* map the character */
  2226.  
  2227.                 if ((pair & 0x00ff) >= 0x80)
  2228.                     pair = (pair & 0xff00) |
  2229.                     vcsMap[(pair & 0x00ff) - 0x80];
  2230.                 *to++ = pair;
  2231.             }
  2232.             write(vcsFd, buf, len * sizeof(ushort));
  2233.         }
  2234.         else write(vcsFd, src, len * sizeof(ushort));
  2235.     }
  2236.     else            /* standard out */
  2237. #endif
  2238.     {
  2239.         int x = dst % TScreen::screenWidth;
  2240.         int y = dst / TScreen::screenWidth;
  2241.  
  2242.         move(y, x);
  2243.         while (len-- > 0)
  2244.         {
  2245.             int code = *src & 0xff;        /* character code */
  2246.             int color = (*src & 0xff00) >> 8; /* color code */
  2247.  
  2248.             attrset(attributeMap[color]);
  2249.             addch(pcToAscii[code]);
  2250.             src++;
  2251.         }
  2252.         move(curY, curX);
  2253.         /* refresh(); */    /* not really necessary */
  2254.     }
  2255. }
  2256.  
  2257. /*
  2258.  * Returns the length of a file.
  2259.  */
  2260.  
  2261. long int filelength(int fd)
  2262. {
  2263.     struct stat s;
  2264.  
  2265.     fstat(fd, &s);
  2266.     return s.st_size;
  2267. }
  2268.  
  2269. /*
  2270.  * Expands a path into its directory and file components.
  2271.  */
  2272.  
  2273. void expandPath(const char *path, char *dir, char *file)
  2274. {
  2275.     char *tag = strrchr(path, '/');
  2276.  
  2277.     /* the path is in the form /dir1/dir2/file ? */
  2278.  
  2279.     if (tag != NULL)
  2280.     {
  2281.         strcpy(file, tag + 1);
  2282.         strncpy(dir, path, tag - path + 1);
  2283.         dir[tag - path + 1] = '\0';
  2284.     }
  2285.     else
  2286.     {
  2287.         /* there is only the file name */
  2288.  
  2289.         strcpy(file, path);
  2290.         dir[0] = '\0';
  2291.     }
  2292. }
  2293.  
  2294. void fexpand(char *path)
  2295. {
  2296.     char dir[PATH_MAX];
  2297.     char file[PATH_MAX];
  2298.     char oldPath[PATH_MAX];
  2299.  
  2300.     expandPath(path, dir, file);
  2301.     getcwd(oldPath, sizeof(oldPath));
  2302.     chdir(dir);
  2303.     getcwd(dir, sizeof(dir));
  2304.     chdir(oldPath);
  2305.     if (strcmp(dir, "/") == 0) sprintf(path, "/%s", file);
  2306.     else sprintf(path, "%s/%s", dir, file);
  2307. }
  2308.