home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / ntconio.c < prev    next >
C/C++ Source or Header  |  1998-09-07  |  17KB  |  835 lines

  1. /*
  2.  * Uses the Win32 console API.
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/ntconio.c,v 1.39 1998/09/07 23:34:14 tom Exp $
  5.  *
  6.  */
  7.  
  8. #include <windows.h>
  9.  
  10. #define    termdef    1            /* don't define "term" external */
  11.  
  12. #include        "estruct.h"
  13. #include        "edef.h"
  14.  
  15. /*
  16.  * Define this if you want to kernel fault win95 when ctrl brk is pressed.
  17.  */
  18. #undef DONT_USE_ON_WIN95
  19.  
  20. #define NROW    128            /* Max Screen size.        */
  21. #define NCOL    256            /* Edit if you want to.         */
  22. #define    MARGIN    8            /* size of minimum margin and    */
  23. #define    SCRSIZ    64            /* scroll size for extended lines */
  24. #define    NPAUSE    200            /* # times thru update to pause */
  25. #define NOKYMAP (-1)
  26.  
  27. #define    AttrColor(b,f)    ((WORD)(((ctrans[b] & 15) << 4) | (ctrans[f] & 15)))
  28.  
  29. static    int    ntgetch        (void);
  30. static    void    ntmove        (int, int);
  31. static    void    nteeol        (void);
  32. static    void    nteeop        (void);
  33. static    void    ntbeep        (void);
  34. static    void    ntopen        (void);
  35. static    void    ntrev        (UINT);
  36. static    int    ntcres        (const char *);
  37. static    void    ntclose        (void);
  38. static    void    ntputc        (int);
  39. static    int    nttypahead    (void);
  40. static    void    ntkopen        (void);
  41. static    void    ntkclose    (void);
  42. #if OPT_COLOR
  43. static    void    ntfcol        (int);
  44. static    void    ntbcol        (int);
  45. #endif
  46. static    void    ntflush        (void);
  47. static    void    ntscroll    (int, int, int);
  48. #if OPT_ICURSOR
  49. static    void    nticursor    (int);
  50. #endif
  51. #if OPT_TITLE
  52. static    void    nttitle        (char *);
  53. #endif
  54.  
  55. static HANDLE hConsoleOutput;        /* handle to the console display */
  56. static HANDLE hOldConsoleOutput;    /* handle to the old console display */
  57. static HANDLE hConsoleInput;
  58. static CONSOLE_SCREEN_BUFFER_INFO csbi;
  59. static WORD originalAttribute;
  60.  
  61. static int    cfcolor = -1;        /* current forground color */
  62. static int    cbcolor = -1;        /* current background color */
  63. static int    nfcolor = -1;        /* normal foreground color */
  64. static int    nbcolor = -1;        /* normal background color */
  65. static int    crow = -1;        /* current row */
  66. static int    ccol = -1;        /* current col */
  67. static int    keyboard_open = FALSE;    /* keyboard is open */
  68. static int    keyboard_was_closed = TRUE;
  69.  
  70. /* ansi to ibm color translation table */
  71. static    const char *initpalettestr = "0 4 2 6 1 5 3 7 8 12 10 14 9 13 11 15";
  72. /* black, red, green, yellow, blue, magenta, cyan, white   */
  73.  
  74. static    char    linebuf[NCOL];
  75. static    int    bufpos = 0;
  76.  
  77. static  void    scflush  (void);
  78.  
  79. /*
  80.  * Standard terminal interface dispatch table. None of the fields point into
  81.  * "termio" code.
  82.  */
  83.  
  84. TERM    term    = {
  85.     NROW,
  86.     NROW,
  87.     NCOL,
  88.     NCOL,
  89.     MARGIN,
  90.     SCRSIZ,
  91.     NPAUSE,
  92.     ntopen,
  93.     ntclose,
  94.     ntkopen,
  95.     ntkclose,
  96.     ntgetch,
  97.     ntputc,
  98.     nttypahead,
  99.     ntflush,
  100.     ntmove,
  101.     nteeol,
  102.     nteeop,
  103.     ntbeep,
  104.     ntrev,
  105.     ntcres,
  106. #if OPT_COLOR
  107.     ntfcol,
  108.     ntbcol,
  109.     set_ctrans,
  110. #else
  111.     null_t_setfor,
  112.     null_t_setback,
  113.     null_t_setpal,
  114. #endif
  115.     ntscroll,
  116.     null_t_pflush,
  117. #if OPT_ICURSOR
  118.     nticursor,
  119. #else
  120.     null_t_icursor,
  121. #endif
  122. #if OPT_TITLE
  123.     nttitle,
  124. #else
  125.     null_t_title,
  126. #endif
  127.     null_t_watchfd,
  128.     null_t_unwatchfd,
  129. };
  130.  
  131.  
  132.  
  133. #if OPT_ICURSOR
  134. static void
  135. nticursor(int cmode)
  136. {
  137.     CONSOLE_CURSOR_INFO cci;
  138.  
  139.     switch (cmode) {
  140.     case -1:
  141.         cci.dwSize = 0;
  142.         cci.bVisible = FALSE;
  143.         break;
  144.     case 0:
  145.         cci.dwSize = 1;
  146.         cci.bVisible = TRUE;
  147.         break;
  148.     case 1:
  149.         cci.dwSize = 100;
  150.         cci.bVisible = TRUE;
  151.         break;
  152.     }
  153.     SetConsoleCursorInfo(hConsoleOutput, &cci);
  154. }
  155. #endif
  156.  
  157. #if OPT_TITLE
  158. static void
  159. nttitle(char *title)        /* set the current window title */
  160. {
  161.     SetConsoleTitle(title);
  162. }
  163. #endif
  164.  
  165. #if OPT_COLOR
  166. static void
  167. ntfcol(int color)        /* set the current output color */
  168. {
  169.     scflush();
  170.     nfcolor = cfcolor = color;
  171. }
  172.  
  173. static void
  174. ntbcol(int color)        /* set the current background color */
  175. {
  176.     scflush();
  177.     nbcolor = cbcolor = color;
  178. }
  179. #endif
  180.  
  181. static void
  182. scflush(void)
  183. {
  184.     if (bufpos) {
  185.         COORD coordCursor;
  186.         DWORD written;
  187.  
  188.         coordCursor.X = ccol;
  189.         coordCursor.Y = crow;
  190.         WriteConsoleOutputCharacter(
  191.             hConsoleOutput, linebuf, bufpos, coordCursor, &written
  192.         );
  193.         FillConsoleOutputAttribute(
  194.             hConsoleOutput, AttrColor(cbcolor, cfcolor),
  195.             bufpos, coordCursor, &written
  196.         );
  197.         ccol += bufpos;
  198.         bufpos = 0;
  199.     }
  200. }
  201.  
  202. static void
  203. ntflush(void)
  204. {
  205.     COORD coordCursor;
  206.  
  207.     scflush();
  208.     coordCursor.X = ccol;
  209.     coordCursor.Y = crow;
  210.     SetConsoleCursorPosition(hConsoleOutput, coordCursor);
  211. }
  212.  
  213. static void
  214. ntmove(int row, int col)
  215. {
  216.     scflush();
  217.     crow = row;
  218.     ccol = col;
  219. }
  220.  
  221. /* erase to the end of the line */
  222. static void
  223. nteeol(void)
  224. {
  225.     DWORD written;
  226.     COORD coordCursor;
  227.  
  228.     scflush();
  229.     coordCursor.X = ccol;
  230.     coordCursor.Y = crow;
  231.     FillConsoleOutputCharacter(
  232.         hConsoleOutput, ' ', csbi.dwMaximumWindowSize.X - ccol,
  233.         coordCursor, &written
  234.     );
  235.     FillConsoleOutputAttribute(
  236.         hConsoleOutput, AttrColor(cbcolor, cfcolor),
  237.         csbi.dwMaximumWindowSize.X - ccol, coordCursor, &written
  238.     );
  239. }
  240.  
  241. /*
  242.  * vile very rarely generates any of the ASCII printing control characters
  243.  * except for a few hand coded routines but we have to support them anyway.
  244.  */
  245.  
  246. /* put a character at the current position in the current colors */
  247. static void
  248. ntputc(int ch)
  249. {
  250.     /* This is an optimization for the most common case. */
  251.     if (ch >= ' ') {
  252.         linebuf[bufpos++] = ch;
  253.         return;
  254.     }
  255.  
  256.     switch (ch) {
  257.  
  258.     case '\b':
  259.         scflush();
  260.         if (ccol)
  261.             ccol--;
  262.         break;
  263.  
  264.     case '\a':
  265.         ntbeep();
  266.         break;
  267.  
  268.     case '\t':
  269.         scflush();
  270.         do
  271.             linebuf[bufpos++] = ' ';
  272.         while ((ccol + bufpos) % 8 != 0);
  273.         break;
  274.  
  275.     case '\r':
  276.         scflush();
  277.         ccol = 0;
  278.         break;
  279.  
  280.     case '\n':
  281.         scflush();
  282.         if (crow < csbi.dwMaximumWindowSize.Y - 1)
  283.             crow++;
  284.         else
  285.             ntscroll(1, 0, csbi.dwMaximumWindowSize.Y - 1);
  286.         break;
  287.  
  288.     default:
  289.         linebuf[bufpos++] = ch;
  290.         break;
  291.     }
  292. }
  293.  
  294. static void
  295. nteeop(void)
  296. {
  297.     DWORD cnt;
  298.     DWORD written;
  299.     COORD coordCursor;
  300.  
  301.     scflush();
  302.     coordCursor.X = ccol;
  303.     coordCursor.Y = crow;
  304.     cnt = csbi.dwMaximumWindowSize.X - ccol
  305.         + (csbi.dwMaximumWindowSize.Y - crow - 1)
  306.         * csbi.dwMaximumWindowSize.X;
  307.     FillConsoleOutputCharacter(
  308.         hConsoleOutput, ' ', cnt, coordCursor, &written
  309.     );
  310.     FillConsoleOutputAttribute(
  311.         hConsoleOutput, AttrColor(cbcolor, cfcolor), cnt,
  312.         coordCursor, &written
  313.     );
  314. }
  315.  
  316. static void
  317. ntrev(UINT attr)        /* change video state */
  318. {
  319.     scflush();
  320.     cbcolor = nbcolor;
  321.     cfcolor = nfcolor;
  322.     if (attr) {
  323.         if (attr & VASPCOL)
  324.             cfcolor = (attr & (NCOLORS - 1));
  325.         else if (attr == VABOLD)
  326.             cfcolor |= FOREGROUND_INTENSITY;
  327.         else if (attr == VAITAL)
  328.             cbcolor |= BACKGROUND_INTENSITY;
  329.         else if (attr & VACOLOR)
  330.             cfcolor = ((VCOLORNUM(attr)) & (NCOLORS - 1));
  331.  
  332.         if (attr & (VASEL|VAREV)) {  /* reverse video? */
  333.             int temp = cfcolor;
  334.             cfcolor = cbcolor;
  335.             cbcolor = temp;
  336.         }
  337.     }
  338. }
  339.  
  340. static int
  341. ntcres(const char *res)    /* change screen resolution */
  342. {
  343.     scflush();
  344.     return 0;
  345. }
  346.  
  347. #if    OPT_FLASH
  348. static void
  349. flash_display()
  350. {
  351.     DWORD length = term.t_ncol * term.t_nrow;
  352.     DWORD got;
  353.     WORD *buf1 = malloc(sizeof(*buf1)*length);
  354.     WORD *buf2 = malloc(sizeof(*buf2)*length);
  355.     static COORD origin;
  356.     ReadConsoleOutputAttribute(hConsoleOutput, buf1, length, origin, &got);
  357.     ReadConsoleOutputAttribute(hConsoleOutput, buf2, length, origin, &got);
  358.     for (got = 0; got < length; got++) {
  359.         buf2[got] ^= (FOREGROUND_INTENSITY|BACKGROUND_INTENSITY);
  360.     }
  361.     WriteConsoleOutputAttribute(hConsoleOutput, buf2, length, origin, &got);
  362.     Sleep(200);
  363.     WriteConsoleOutputAttribute(hConsoleOutput, buf1, length, origin, &got);
  364.     free(buf1);
  365.     free(buf2);
  366. }
  367. #endif
  368.  
  369. static void
  370. ntbeep(void)
  371. {
  372. #if    OPT_FLASH
  373.     if (global_g_val(GMDFLASH)) {
  374.         flash_display();
  375.         return;
  376.     }
  377. #endif
  378.     MessageBeep(0xffffffff);
  379. }
  380.  
  381. static BOOL WINAPI
  382. nthandler(DWORD ctrl_type)
  383. {
  384.     switch (ctrl_type) {
  385.     case CTRL_CLOSE_EVENT:
  386.     case CTRL_LOGOFF_EVENT:
  387.     case CTRL_SHUTDOWN_EVENT:
  388.         imdying(1);
  389.         break;
  390.     }
  391.     return TRUE;
  392. }
  393.  
  394. static void
  395. ntopen(void)
  396. {
  397.     TRACE(("ntopen\n"))
  398.     set_palette(initpalettestr);
  399.     hOldConsoleOutput = 0;
  400.     hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  401.     GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
  402.     if (csbi.dwMaximumWindowSize.Y !=
  403.         csbi.srWindow.Bottom - csbi.srWindow.Top + 1
  404.         || csbi.dwMaximumWindowSize.X !=
  405.         csbi.srWindow.Right - csbi.srWindow.Left + 1) {
  406.         hOldConsoleOutput = hConsoleOutput;
  407.         hConsoleOutput = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE,
  408.             0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
  409.         SetConsoleActiveScreenBuffer(hConsoleOutput);
  410.         GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
  411.     }
  412.     originalAttribute = csbi.wAttributes;
  413.     crow = csbi.dwCursorPosition.Y;
  414.     ccol = csbi.dwCursorPosition.X;
  415.     nfcolor = cfcolor = gfcolor;
  416.     nbcolor = cbcolor = gbcolor;
  417.     newscreensize(csbi.dwMaximumWindowSize.Y, csbi.dwMaximumWindowSize.X);
  418.     hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
  419.     SetConsoleCtrlHandler(nthandler, TRUE);
  420. }
  421.  
  422. static void
  423. ntclose(void)
  424. {
  425.     TRACE(("ntclose\n"))
  426.     scflush();
  427.     ntmove(term.t_nrow - 1, 0);
  428.     nteeol();
  429.     ntflush();
  430.     SetConsoleTextAttribute(hConsoleOutput, originalAttribute);
  431.     if (hOldConsoleOutput) {
  432.         SetConsoleActiveScreenBuffer(hOldConsoleOutput);
  433.         CloseHandle(hConsoleOutput);
  434.     }
  435.     SetConsoleCtrlHandler(nthandler, FALSE);
  436.     SetConsoleMode(hConsoleInput, ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
  437.     keyboard_open = FALSE;
  438. }
  439.  
  440. static void
  441. ntkopen(void)    /* open the keyboard */
  442. {
  443.     TRACE(("ntkopen (open:%d, was-closed:%d)\n", keyboard_open, keyboard_was_closed))
  444.     if (keyboard_open)
  445.         return;
  446.     if (hConsoleOutput)
  447.         SetConsoleActiveScreenBuffer(hConsoleOutput);
  448.     keyboard_open = TRUE;
  449. #ifdef DONT_USE_ON_WIN95
  450.     SetConsoleCtrlHandler(NULL, TRUE);
  451. #endif
  452.     SetConsoleMode(hConsoleInput, ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT);
  453. }
  454.  
  455. static void
  456. ntkclose(void)    /* close the keyboard */
  457. {
  458.     TRACE(("ntkclose\n"))
  459.     if (!keyboard_open)
  460.         return;
  461.     keyboard_open = FALSE;
  462.     keyboard_was_closed = TRUE;
  463.     if (hOldConsoleOutput)
  464.         SetConsoleActiveScreenBuffer(hOldConsoleOutput);
  465. #ifdef DONT_USE_ON_WIN95
  466.     SetConsoleCtrlHandler(NULL, FALSE);
  467. #endif
  468. }
  469.  
  470. static struct {
  471.     int    windows;
  472.     int    vile;
  473. } keyxlate[] = {
  474.     { VK_NEXT,    KEY_Next },
  475.     { VK_PRIOR,    KEY_Prior },
  476.     { VK_END,    KEY_End },
  477.     { VK_HOME,    KEY_Home },
  478.     { VK_LEFT,    KEY_Left },
  479.     { VK_RIGHT,    KEY_Right },
  480.     { VK_UP,    KEY_Up },
  481.     { VK_DOWN,    KEY_Down },
  482.     { VK_INSERT,    KEY_Insert },
  483.     { VK_DELETE,    KEY_Delete },
  484.     { VK_HELP,    KEY_Help },
  485.     { VK_SELECT,    KEY_Select },
  486. #if 0
  487.     /* Merely pressing the Alt key generates a VK_MENU key event. */
  488.     { VK_MENU,    KEY_Menu },
  489. #endif
  490.     { VK_F1,    KEY_F1 },
  491.     { VK_F2,    KEY_F2 },
  492.     { VK_F3,    KEY_F3 },
  493.     { VK_F4,    KEY_F4 },
  494.     { VK_F5,    KEY_F5 },
  495.     { VK_F6,    KEY_F6 },
  496.     { VK_F7,    KEY_F7 },
  497.     { VK_F8,    KEY_F8 },
  498.     { VK_F9,    KEY_F9 },
  499.     { VK_F10,    KEY_F10 },
  500.     { VK_F11,    KEY_F11 },
  501.     { VK_F12,    KEY_F12 },
  502.     { VK_F13,    KEY_F13 },
  503.     { VK_F14,    KEY_F14 },
  504.     { VK_F15,    KEY_F15 },
  505.     { VK_F16,    KEY_F16 },
  506.     { VK_F17,    KEY_F17 },
  507.     { VK_F18,    KEY_F18 },
  508.     { VK_F19,    KEY_F19 },
  509.     { VK_F20,    KEY_F20 },
  510.     /* Allow ^-6 to invoke the alternate-buffer command, a la Unix.  */
  511.     { '6',        '6' },
  512. };
  513.  
  514. static int savedChar;
  515. static int saveCount = 0;
  516.  
  517. static int
  518. decode_key_event(INPUT_RECORD *irp)
  519. {
  520.     int key;
  521.     int i;
  522.  
  523.     if (!irp->Event.KeyEvent.bKeyDown)
  524.     return (NOKYMAP);
  525.  
  526.     if ((key = (unsigned char) irp->Event.KeyEvent.uChar.AsciiChar) != 0)
  527.     return key;
  528.  
  529.     for (i = 0; i < TABLESIZE(keyxlate); i++)
  530.     {
  531.     if (keyxlate[i].windows == irp->Event.KeyEvent.wVirtualKeyCode)
  532.     {
  533.         DWORD state = irp->Event.KeyEvent.dwControlKeyState;
  534.  
  535.         /*
  536.          * If this key is modified in some way, we'll prefer to use the
  537.          * Win32 definition.  But only for the modifiers that we
  538.          * recognize.  Specifically, we don't care about ENHANCED_KEY,
  539.          * since we already have portable pageup/pagedown and arrow key
  540.          * bindings that would be lost if we used the Win32-only
  541.          * definition.
  542.          */
  543.         if (state &
  544.         (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED
  545.         | LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED
  546.         | SHIFT_PRESSED))
  547.         {
  548.         key = W32_KEY | keyxlate[i].windows;
  549.         if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
  550.             key |= W32_CTRL;
  551.         if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
  552.             key |= W32_ALT;
  553.         if (state & SHIFT_PRESSED)
  554.             key |= W32_SHIFT;
  555.         }
  556.         else
  557.         key = keyxlate[i].vile;
  558.         break;
  559.     }
  560.     }
  561.     if (key == 0)
  562.     return (NOKYMAP);
  563.  
  564.     return key;
  565. }
  566.  
  567. static void
  568. handle_mouse_event(MOUSE_EVENT_RECORD mer)
  569. {
  570.     int buttondown = FALSE;
  571.     COORD first, current, last;
  572.     int state;
  573.  
  574.     for_ever {
  575.         switch (mer.dwEventFlags) {
  576.         case 0:
  577.             state = mer.dwButtonState;
  578.             if (state == 0) {
  579.                 if (!buttondown)
  580.                     return;
  581.                 buttondown = FALSE;
  582.                 sel_yank(0);
  583.                 return;
  584.             }
  585.             if (state & FROM_LEFT_1ST_BUTTON_PRESSED) {
  586.                 if (buttondown) {
  587.                     if (state & RIGHTMOST_BUTTON_PRESSED) {
  588.                         sel_release();
  589.                         (void)update(TRUE);
  590.                         return;
  591.                     }
  592.                     break;
  593.                 }
  594.                 buttondown = TRUE;
  595.                 first = mer.dwMousePosition;
  596.                 if (!setcursor(first.Y, first.X))
  597.                     return;
  598.                 (void)sel_begin();
  599.                 (void)update(TRUE);
  600.                 break;
  601.             }
  602.             break;
  603.  
  604.         case MOUSE_MOVED:
  605.             if (!buttondown)
  606.                 return;
  607.             current = mer.dwMousePosition;
  608.             if (!setcursor(current.Y, current.X))
  609.                 break;
  610.             last = current;
  611.             if (mer.dwControlKeyState &
  612.                             (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
  613.             {
  614.                 (void)sel_setshape(RECTANGLE);
  615.             }
  616.             if (!sel_extend(TRUE, TRUE))
  617.                 break;
  618.             (void)update(TRUE);
  619.             break;
  620.         }
  621.  
  622.         for_ever {
  623.             INPUT_RECORD ir;
  624.             DWORD nr;
  625.             int key;
  626.  
  627.             if (!ReadConsoleInput(hConsoleInput, &ir, 1, &nr))
  628.                 imdying(0);
  629.             switch (ir.EventType) {
  630.             case KEY_EVENT:
  631.                 key = decode_key_event(&ir);
  632.                 if (key == ESC) {
  633.                     sel_release();
  634.                     (void)update(TRUE);
  635.                     return;
  636.                 }
  637.                 continue;
  638.  
  639.             case MOUSE_EVENT:
  640.                 mer = ir.Event.MouseEvent;
  641.                 break;
  642.             }
  643.             break;
  644.         }
  645.     }
  646. }
  647.  
  648. static int
  649. ntgetch(void)
  650. {
  651.     INPUT_RECORD ir;
  652.     DWORD nr;
  653.     int key;
  654.  
  655.     if (saveCount > 0) {
  656.         saveCount--;
  657.         return savedChar;
  658.     }
  659.  
  660.     for_ever {
  661.         if (!ReadConsoleInput(hConsoleInput, &ir, 1, &nr))
  662.             imdying(0);
  663.         switch(ir.EventType) {
  664.  
  665.         case KEY_EVENT:
  666.             key = decode_key_event(&ir);
  667.             if (key == NOKYMAP)
  668.                 continue;
  669.             if (ir.Event.KeyEvent.wRepeatCount > 1) {
  670.                 saveCount = ir.Event.KeyEvent.wRepeatCount - 1;
  671.                 savedChar = key;
  672.             }
  673.             return key;
  674.  
  675.         case WINDOW_BUFFER_SIZE_EVENT:
  676.             newscreensize(
  677.                 ir.Event.WindowBufferSizeEvent.dwSize.Y,
  678.                 ir.Event.WindowBufferSizeEvent.dwSize.X
  679.             );
  680.             GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
  681.             continue;
  682.  
  683.         case MOUSE_EVENT:
  684.             handle_mouse_event(ir.Event.MouseEvent);
  685.             continue;
  686.  
  687.         }
  688.     }
  689. }
  690.  
  691. /*
  692.  * The function `kbhit' returns true if there are *any* input records
  693.  * available.  We need to define our own type ahead routine because
  694.  * otherwise events which we will discard (like pressing or releasing
  695.  * the Shift key) can block screen updates because `ntgetch' won't
  696.  * return until a ordinary key event occurs.
  697.  */
  698.  
  699. static int
  700. nttypahead()
  701. {
  702.     INPUT_RECORD ir;
  703.     DWORD nr;
  704.     int key;
  705.  
  706.     if (!keyboard_open)
  707.         return 0;
  708.  
  709.     if (saveCount > 0)
  710.         return 1;
  711.  
  712.     for (;;) {
  713.         if (!PeekConsoleInput(hConsoleInput, &ir, 1, &nr))
  714.             return 0;
  715.  
  716.         if (nr == 0)
  717.             break;
  718.  
  719.         switch(ir.EventType) {
  720.  
  721.         case KEY_EVENT:
  722.             key = decode_key_event(&ir);
  723.             if (key < 0) {
  724.                 ReadConsoleInput(hConsoleInput, &ir, 1, &nr);
  725.                 continue;
  726.             }
  727.             return 1;
  728.  
  729.         default:
  730.             /* Ignore type-ahead for non-keyboard events. */
  731.             return 0;
  732.         }
  733.     }
  734.  
  735.     return 0;
  736. }
  737.  
  738. /*
  739.  * Move 'n' lines starting at 'from' to 'to'
  740.  *
  741.  * OPT_PRETTIER_SCROLL is prettier but slower -- it scrolls a line at a time
  742.  *    instead of all at once.
  743.  */
  744.  
  745. /* move howmany lines starting at from to to */
  746. static void
  747. ntscroll(int from, int to, int n)
  748. {
  749.     SMALL_RECT sRect;
  750.     COORD dest;
  751.     CHAR_INFO fill;
  752.     int       scroll_pause;
  753.  
  754.     scflush();
  755.     if (to == from)
  756.         return;
  757. #if OPT_PRETTIER_SCROLL
  758.     if (absol(from-to) > 1) {
  759.         ntscroll(from, (from<to) ? to-1:to+1, n);
  760.         if (from < to)
  761.             from = to-1;
  762.         else
  763.             from = to+1;
  764.     }
  765. #endif
  766.     fill.Char.AsciiChar = ' ';
  767.     fill.Attributes = AttrColor(cbcolor, cfcolor);
  768.  
  769.     sRect.Left = 0;
  770.     sRect.Top = from;
  771.     sRect.Right = csbi.dwMaximumWindowSize.X - 1;
  772.     sRect.Bottom = from + n - 1;
  773.  
  774.     dest.X = 0;
  775.     dest.Y = to;
  776.  
  777.     ScrollConsoleScreenBuffer(hConsoleOutput, &sRect, NULL, dest, &fill);
  778.     if ((scroll_pause = global_g_val(GVAL_SCROLLPAUSE)) > 0)
  779.     {
  780.         /*
  781.          * If the user has cheap video HW (1 MB or less) and
  782.          * there's a busy background app (say, dev studio), then
  783.          * the console version of vile can exhibit serious repaint
  784.          * problems when the display is rapidly scrolled.  By
  785.          * inserting a user-defined sleep after the scroll, the
  786.          * video HW has a chance to properly paint before the
  787.          * next scroll operation.
  788.          */
  789.  
  790.         Sleep(scroll_pause);
  791.     }
  792.  
  793. #if !OPT_PRETTIER_SCROLL
  794.     if (absol(from - to) > n) {
  795.         DWORD cnt;
  796.         DWORD written;
  797.         COORD coordCursor;
  798.  
  799.         coordCursor.X = 0;
  800.         if (to > from) {
  801.             coordCursor.Y = from + n;
  802.             cnt = to - from - n;
  803.         }
  804.         else {
  805.             coordCursor.Y = to + n;
  806.             cnt = from - to - n;
  807.         }
  808.         cnt *= csbi.dwMaximumWindowSize.X;
  809.         FillConsoleOutputCharacter(
  810.             hConsoleOutput, ' ', cnt, coordCursor, &written
  811.         );
  812.         FillConsoleOutputAttribute(
  813.             hConsoleOutput, AttrColor(cbcolor, cfcolor), cnt,
  814.             coordCursor, &written
  815.         );
  816.     }
  817. #endif
  818. }
  819.  
  820. void
  821. ntcons_reopen(void)
  822. {
  823.     /* If we are coming back from a shell command, pick up the current window
  824.      * size, since that may have changed due to a 'mode con' command.  Run
  825.      * this after the 'pressreturn()' call, since otherwise that gets lost
  826.      * by side-effects of this code.
  827.      */
  828.     if (keyboard_was_closed) {
  829.         CONSOLE_SCREEN_BUFFER_INFO temp;
  830.         keyboard_was_closed = FALSE;
  831.         GetConsoleScreenBufferInfo(hConsoleOutput, &temp);
  832.         newscreensize(temp.dwMaximumWindowSize.Y, temp.dwMaximumWindowSize.X);
  833.     }
  834. }
  835.