/*$Header: /p/tcsh/cvsroot/tcsh/win32/console.c,v 1.9 2006/08/27 01:13:28 amold Exp $*/ /*- * Copyright (c) 1980, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * console.c: hacks to do various cursor movement/attribute things * -amol */ #define WIN32_LEAN_AND_MEAN #include #include #include #include "ntport.h" // int to SHORT. caused by all the stupid functions that take WORDs #pragma warning(disable:4244) void ScrollBuf(HANDLE,CONSOLE_SCREEN_BUFFER_INFO*,int); void NT_MoveToLineOrChar(int ,int ) ; WORD get_attributes(); #define FSHIN 16 /* Preferred desc for shell input */ #define FSHOUT 17 /* Preferred desc for shell input */ #define FOREGROUND_BLACK (FOREGROUND_RED |FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_WHITE 0 #define BACKGROUND_BLACK (BACKGROUND_RED |BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_WHITE 0 static WORD wNormalAttributes; static int nt_is_raw; // // The following are used to optimize some console routines. It avoids having // to call GetConsoleScreenBufferInfo. // Seems to have helped the speed a bit. -amol // HANDLE ghstdout; HANDLE ghReverse; // // This function is called to set the values for above variables. // void redo_console(void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; HANDLE hTemp= GetStdHandle(STD_OUTPUT_HANDLE); WORD dbga; DWORD wrote; COORD origin = {0,0}; if (!DuplicateHandle(GetCurrentProcess(),hTemp,GetCurrentProcess(), &ghstdout,0,TRUE,DUPLICATE_SAME_ACCESS) ) { ; } if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) { wNormalAttributes = FOREGROUND_BLACK | BACKGROUND_WHITE; } else wNormalAttributes = scrbuf.wAttributes; ghReverse = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); dbga = ((wNormalAttributes & 0x00f0) >> 4) | ((wNormalAttributes & 0x000f) << 4) ; FillConsoleOutputAttribute(ghReverse,dbga, scrbuf.dwSize.X*scrbuf.dwSize.Y, origin, &wrote); } void nt_term_cleanup(void) { CloseHandle(ghstdout); } void nt_term_init() { DWORD dwmode; HANDLE hinput =GetStdHandle(STD_INPUT_HANDLE); if (!GetConsoleMode(hinput,&dwmode) ){ ; } if(!SetConsoleMode(hinput,dwmode | ENABLE_WINDOW_INPUT) ){ return; } redo_console(); return; } int do_nt_check_cooked_mode(void) { return !nt_is_raw; } void do_nt_raw_mode() { DWORD dwmode; HANDLE hinput =(HANDLE)_get_osfhandle(FSHIN); if (hinput == INVALID_HANDLE_VALUE) return; if (!GetConsoleMode(hinput,&dwmode) ){ ; } if(!SetConsoleMode(hinput,dwmode & (~( ENABLE_LINE_INPUT |ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT)| ENABLE_WINDOW_INPUT ) ) ){ return; } nt_is_raw = 1; return; } void do_nt_cooked_mode() { DWORD dwmode; HANDLE hinput =(HANDLE)_get_osfhandle(FSHIN); if (hinput == INVALID_HANDLE_VALUE) return; if (!GetConsoleMode(hinput,&dwmode) ){ ; } if(!SetConsoleMode(hinput,dwmode | ( ( ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) ) ) ){ } nt_is_raw = 0; return; } // // this function is a bit ugly, but I don't know how to do it better // -amol // int nt_ClearEOL( void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; HANDLE hStdout =ghstdout ; DWORD numwrote; char errbuf[128];/*FIXME: uninitialized*/ int num=0; COORD savepos; if (hStdout == INVALID_HANDLE_VALUE){ ExitProcess(0xFFFF); } if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { return 0 ; } num =2048; savepos = scrbuf.dwCursorPosition; if (!FillConsoleOutputCharacter(hStdout,' ',num,scrbuf.dwCursorPosition, &numwrote) ){ dprintf("error from FillCons %s",errbuf); } else if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, num, scrbuf.dwCursorPosition,&numwrote)) { dprintf("error from FillConsAttr %s",errbuf); } return 0; } void nt_move_next_tab(void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; HANDLE hStdout = ghstdout; int where; if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { ; } where = 8 - (scrbuf.dwCursorPosition.X+1)%8; scrbuf.dwCursorPosition.X += where; if (!SetConsoleCursorPosition(hStdout, scrbuf.dwCursorPosition) ) { ; } } void NT_VisibleBell(void) { if(ghReverse != INVALID_HANDLE_VALUE) { SetConsoleActiveScreenBuffer(ghReverse); Sleep(100); SetConsoleActiveScreenBuffer(ghstdout); } } void NT_WrapHorizontal(void) { SMALL_RECT wnd; CONSOLE_SCREEN_BUFFER_INFO scrbuf; if (ghstdout == INVALID_HANDLE_VALUE){ return; } if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) { return; } //absolute movement wnd.Left = 0;//scrbuf.srWindow.Left ; wnd.Right = scrbuf.srWindow.Right- scrbuf.srWindow.Left + 1; wnd.Top = scrbuf.srWindow.Top; wnd.Bottom = scrbuf.srWindow.Bottom; SetConsoleWindowInfo(ghstdout,TRUE,&wnd); } void ScrollBufHorizontal(HANDLE hOut, CONSOLE_SCREEN_BUFFER_INFO *scrbuf, int where) { SMALL_RECT wnd; int diff; CHAR_INFO chr; //absolute movement wnd.Left = (where - scrbuf->srWindow.Right) + scrbuf->srWindow.Left ; wnd.Right = where; wnd.Top = scrbuf->srWindow.Top; wnd.Bottom = scrbuf->srWindow.Bottom; //diff = scrbuf->srWindow.Right - where; //dprintf("\tdiff1 %d\n",diff); diff = scrbuf->dwSize.X - where -1; if (diff < 0) { //would scroll past console buffer chr.Char.AsciiChar = ' '; chr.Attributes = scrbuf->wAttributes; scrbuf->dwCursorPosition.Y = scrbuf->srWindow.Top ; scrbuf->dwCursorPosition.X = scrbuf->srWindow.Right+ diff; dprintf("scroll diff %d\n",diff); if (!ScrollConsoleScreenBuffer(hOut,&(scrbuf->srWindow), NULL, scrbuf->dwCursorPosition,&chr)) ; return; } SetConsoleWindowInfo(hOut,TRUE,&wnd); } // relative movement of "where". line is 1 if we want to move to a line, // or 0 if the movement is horizontal void NT_MoveToLineOrChar(int where,int line) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; HANDLE hStdout = ghstdout; if (hStdout == INVALID_HANDLE_VALUE){ return; } if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { return; } if (line){ if ( ((scrbuf.dwCursorPosition.Y+where)> (scrbuf.srWindow.Bottom-1)) &&( where >0)){ ScrollBuf(hStdout,&scrbuf,where); scrbuf.dwCursorPosition.Y += where; } else scrbuf.dwCursorPosition.Y += where; } else{ if ( (where> (scrbuf.srWindow.Right)) &&( where >0)){ ScrollBufHorizontal(hStdout,&scrbuf,where); } scrbuf.dwCursorPosition.X = where; } if (scrbuf.dwCursorPosition.X < 0 || scrbuf.dwCursorPosition.Y <0) return; if (!SetConsoleCursorPosition(hStdout, scrbuf.dwCursorPosition) ) { return; } } void ScrollBuf(HANDLE hOut, CONSOLE_SCREEN_BUFFER_INFO *scrbuf,int where) { SMALL_RECT wnd; int diff; CHAR_INFO chr; COORD newpos; wnd.Left = 0; wnd.Right = 0; wnd.Top = where; wnd.Bottom = where; //dwSize is not 0-based, so add 1 to proposed location diff = scrbuf->srWindow.Bottom + where + 1; diff = scrbuf->dwSize.Y - diff; if (diff < 0) { //would scroll past console buffer chr.Char.AsciiChar = ' '; chr.Attributes = scrbuf->wAttributes; newpos.Y = scrbuf->srWindow.Top + diff; newpos.X = scrbuf->srWindow.Left; dprintf("scroll diff %d\n",diff); if (!ScrollConsoleScreenBuffer(hOut,&(scrbuf->srWindow), NULL, newpos,&chr)) ; // need this to be in sync with tcsh scrbuf->dwCursorPosition.Y += diff; return; } SetConsoleWindowInfo(hOut,FALSE,&wnd); } BOOL ConsolePageUpOrDown(BOOL Up) { HANDLE hStdout = ghstdout; CONSOLE_SCREEN_BUFFER_INFO scrbuf; SMALL_RECT srect; short diff; if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { return FALSE; } diff = scrbuf.srWindow.Bottom -scrbuf.srWindow.Top+1 ; if (Up) diff = -diff; if ((scrbuf.srWindow.Top + diff > 0) && (scrbuf.srWindow.Bottom + diff < scrbuf.dwSize.Y)) { srect.Top = diff; srect.Bottom = diff; srect.Left = 0; srect.Right = 0; if (! SetConsoleWindowInfo( hStdout, FALSE, &srect)) { return FALSE; } } return TRUE; } int nt_getsize(int * lins, int * cols, int *visiblecols) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; HANDLE hStdout = ghstdout; if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { ; } *lins = scrbuf.srWindow.Bottom -scrbuf.srWindow.Top+1 ; if(visiblecols) *visiblecols = scrbuf.srWindow.Right -scrbuf.srWindow.Left +1; *cols = scrbuf.dwSize.X; return 1; } void nt_set_size(int lins, int cols) { SMALL_RECT srect; CONSOLE_SCREEN_BUFFER_INFO scrbuf; int expand; /* The screen buffer visible window is specified as co-ordinates * not size. Therefore, it must be zero-based */ cols--; lins--; srect.Left = srect.Top = 0; srect.Right = cols; srect.Bottom = lins; if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) return; expand = 0; if (scrbuf.dwSize.X < cols){ expand = 1; scrbuf.dwSize.X = cols+1; } if (scrbuf.dwSize.Y < lins){ expand = 1; scrbuf.dwSize.Y = lins+1; } if (expand && !SetConsoleScreenBufferSize(ghstdout,scrbuf.dwSize)) return; if(!SetConsoleWindowInfo(ghstdout,TRUE,&srect)){ int err; err=GetLastError(); dprintf("error %d\n",err); } } void NT_ClearEOD(void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; DWORD numwrote; COORD origin; int ht,wt; HANDLE hStdout = ghstdout;//GetStdHandle(STD_OUTPUT_HANDLE); if (hStdout == INVALID_HANDLE_VALUE){ return ; } if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { return ; } origin = scrbuf.dwCursorPosition; ht = scrbuf.dwSize.Y - origin.Y; wt = scrbuf.dwSize.X - origin.X; if(!FillConsoleOutputCharacter(hStdout,' ',ht*wt,origin,&numwrote) ) { return ; } if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, ht*wt, scrbuf.dwCursorPosition,&numwrote)) { return; } return; } void NT_ClearScreen(void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; DWORD numwrote; COORD origin={0,0}; HANDLE hStdout = ghstdout;//GetStdHandle(STD_OUTPUT_HANDLE); if (hStdout == INVALID_HANDLE_VALUE){ ; } if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { ; } origin.X = scrbuf.srWindow.Left; origin.Y = scrbuf.srWindow.Top; if(!FillConsoleOutputCharacter(hStdout,' ',scrbuf.dwSize.X*scrbuf.dwSize.Y, origin,&numwrote) ) { ; } if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, scrbuf.dwSize.X*scrbuf.dwSize.Y,origin,&numwrote)) { ; } if (!SetConsoleCursorPosition(hStdout, origin) ) { // home cursor ; } return; } void NT_ClearScreen_WholeBuffer(void) { CONSOLE_SCREEN_BUFFER_INFO scrbuf; DWORD numwrote; COORD origin={0,0}; HANDLE hStdout = ghstdout; if (hStdout == INVALID_HANDLE_VALUE){ ; } if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { ; } if(!FillConsoleOutputCharacter(hStdout,' ',scrbuf.dwSize.X*scrbuf.dwSize.Y, origin,&numwrote) ) { ; } if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, scrbuf.dwSize.X*scrbuf.dwSize.Y,origin,&numwrote)) { ; } if (!SetConsoleCursorPosition(hStdout, origin) ) { // home cursor ; } return; } #ifndef COLOR_LS_F void set_cons_attr(char *attr2) { char cp[3]; USHORT attr; HANDLE outhandle = (HANDLE)_get_osfhandle(FSHOUT); static WORD old_attribs; CONSOLE_SCREEN_BUFFER_INFO scrbuf; if (!old_attribs) { if(!GetConsoleScreenBufferInfo(outhandle, &scrbuf) ) { return; } old_attribs = scrbuf.wAttributes; } cp[0] = (unsigned char)(attr2[0]); cp[1] = (unsigned char)(attr2[1]); cp[2] = 0; if (cp[0] != 'g' || cp[1] != 'g') attr = (USHORT)strtol(cp,NULL,16); else{ attr = old_attribs; old_attribs=0; } SetConsoleTextAttribute(outhandle, attr ); } #endif /* !COLOR_LS_F */ /* color escape sequences (ISO 6429, aixterm) - nayuta */ WORD get_attributes() { CONSOLE_SCREEN_BUFFER_INFO scrbuf; if (!GetConsoleScreenBufferInfo(ghstdout, &scrbuf)) return 0x70; // ERROR: return white background, black text return scrbuf.wAttributes; } #ifndef COMMON_LVB_REVERSE_VIDEO #define COMMON_LVB_REVERSE_VIDEO 0x4000 #define COMMON_LVB_UNDERSCORE 0x8000 #endif void set_attributes(const unsigned char *color) { static const int colors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; WORD wAttributes; const char *t; if (color[0] == '\x1b' && color[1] == '[') color += 2; if (!('0' <= color[0] && color[0] <= '9')) { SetConsoleTextAttribute(ghstdout, wNormalAttributes); return; } wAttributes = get_attributes(); t = (char*)color; while (t) { int n = atoi(t); if ((t = strchr(t, ';')) != NULL) t++; if (n == 0) // Normal (default) wAttributes = wNormalAttributes; else if (n == 1) // Bold wAttributes |= FOREGROUND_INTENSITY; else if (n == 4) // Underlined wAttributes |= COMMON_LVB_UNDERSCORE; else if (n == 5) // Blink (appears as BACKGROUND_INTENSITY) wAttributes |= BACKGROUND_INTENSITY; else if (n == 7) // Inverse wAttributes |= COMMON_LVB_REVERSE_VIDEO; else if (n == 21) // Not bold wAttributes &= ~FOREGROUND_INTENSITY; else if (n == 24) // Not underlined wAttributes &= ~COMMON_LVB_UNDERSCORE; else if (n == 25) // Steady (not blinking) wAttributes &= ~BACKGROUND_INTENSITY; else if (n == 27) // Positive (not inverse) wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; else if (30 <= n && n <= 37) // Set foreground color wAttributes = (wAttributes & ~0x0007) | colors[n - 30]; else if (n == 39) // Set foreground color to default wAttributes = (wAttributes & ~0x0007) | (wNormalAttributes & 0x0007); else if (40 <= n && n <= 47) // Set background color wAttributes = (wAttributes & ~0x0070) | (colors[n - 40] << 4); else if (n == 49) // Set background color to default wAttributes = (wAttributes & ~0x0070) | (wNormalAttributes & 0x0070); else if (90 <= n && n <= 97) // Set foreground color (bright) wAttributes = (wAttributes & ~0x0007) | colors[n - 90] | FOREGROUND_INTENSITY; else if (100 <= n && n <= 107) // Set background color (bright) wAttributes = (wAttributes & ~0x0070) | (colors[n - 100] << 4) | BACKGROUND_INTENSITY; else // (default) wAttributes = wNormalAttributes; } // Though Windows' console supports COMMON_LVB_REVERSE_VIDEO, // it seems to be buggy. So we must simulate it. if (wAttributes & COMMON_LVB_REVERSE_VIDEO) wAttributes = (wAttributes & COMMON_LVB_UNDERSCORE) | ((wAttributes & 0x00f0) >> 4) | ((wAttributes & 0x000f) << 4); SetConsoleTextAttribute(ghstdout, wAttributes); } void StartHighlight(void) { } void StopHighlight(void) { }