From a7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 6 Jul 2014 18:04:32 +0200 Subject: Imported Upstream version 2.9.3 --- util/AnsiTerm.cpp | 1892 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1892 insertions(+) create mode 100644 util/AnsiTerm.cpp (limited to 'util/AnsiTerm.cpp') diff --git a/util/AnsiTerm.cpp b/util/AnsiTerm.cpp new file mode 100644 index 0000000..be94465 --- /dev/null +++ b/util/AnsiTerm.cpp @@ -0,0 +1,1892 @@ +/* + * AnsiTerm.cpp + * Windows ANSI Terminal Emulation + * + * Author: Robert Nelson robertnelson at users.sourceforge.net + * Copyright (c) 2009 Robert Nelson + * + * 10/07/09 Robert Nelson - Created + * 10/08/09 Robert Nelson + * - Fixed bug with resetting attribute to Black on Black on exit + * - Fixed setting of attribute when erasing + * - Added automatic handling of buffer resize events + * - Added display of unrecognized escape sequences + * 10/15/09 Robert Nelson + * - Fixed display problems caused by custom ColorTable used by cmd.exe + * - Fixed cursor positioning problems with OriginMode. + * - Changed to use block cursor because I think its more terminal like :-) + * - Added Reset handling + * - Added Cursor Show / Hide + * 10/16/09 Robert Nelson + * - Better handling of ColorTable. + * 10/17/09 Robert Nelson + * - Use GetProcAddress for (Get/Set)ConsoleScreenBufferInfoEx since they + * are only available on Vista and beyond. + * + * Todo: + * - Implement soft tabs + */ + +/* +Copyright (c) 2009, Robert Nelson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. 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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. +*/ +#include +#include +#include +#include "AnsiTerm.h" + +extern "C" unsigned char fCRLF; +extern "C" void dbglog( char *pattn, ... ); + +CAnsiTerm::CSICode CAnsiTerm::s_CSITable[] = +{ + { '[', DS_CSIParam }, + { '#', DS_DECPrivate }, + { '(', DS_SelectG0 }, + { ')', DS_SelectG1 }, + { '=', DS_None, &ProcessDECKPAM }, // Keypad Application Mode + { '>', DS_None, &ProcessDECKPNM }, // Keypad Numeric Mode + { '7', DS_None, &ProcessDECSC }, // Save Cursor + { '8', DS_None, &ProcessDECRC }, // Restore Cursor + { 'D', DS_None, &ProcessIND }, // Index + { 'E', DS_None, &ProcessNEL }, // Next Line + { 'H', DS_None, &ProcessHTS }, // Horizontal Tab Set + { 'M', DS_None, &ProcessRI }, // Reverse Index + { 'Z', DS_None, &ProcessDECID }, // Identify Terminal + { 'c', DS_None, &ProcessRIS }, // Reset to Initial State + { 's', DS_None, &ProcessSCP }, // Save Cursor Position + { 'u', DS_None, &ProcessRCP }, // Restore Cursor Position + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_DECFunction[] = +{ + { '3', &ProcessDECDHLT }, // Double Height Line Top + { '4', &ProcessDECDHLB }, // Double Height Line Bottom + { '5', &ProcessDECSWL }, // Single Width Line + { '6', &ProcessDECDWL }, // Double Width Line + { '8', &ProcessDECALN }, // Screen Alignment Display + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_CSIFunction[] = +{ + { 'A', &ProcessCUU }, // Cursor Up + { 'B', &ProcessCUD }, // Cursor Down + { 'C', &ProcessCUF }, // Cursor Forward + { 'D', &ProcessCUB }, // Cursor Backward + { 'H', &ProcessCUP }, // Cursor Position + { 'J', &ProcessED }, // Erase in Display + { 'K', &ProcessEL }, // Erase in Line + { 'c', &ProcessDA }, // Device Attributes + { 'f', &ProcessHVP }, // Horizontal and Vertical Position + { 'g', &ProcessTBC }, // Tabulation Clear + { 'h', &ProcessSM }, // Set Mode + { 'l', &ProcessRM }, // Reset Mode + { 'm', &ProcessSGR }, // Select Graphics Rendition + { 'n', &ProcessDSR }, // Device Status Report + { 'q', &ProcessDECLL }, // DEC Load LEDs + { 'r', &ProcessDECSTBM }, // DEC Set Top and Bottom Margins + { 'x', &ProcessDECREQTPARM }, // Request Terminal Parameters + { 'y', &ProcessDECTST }, // Invoke Confidence Test + { '\0' } +}; + +wchar_t CAnsiTerm::s_GraphicChars[kMaxGraphicsChar - kMinGraphicsChar + 1] = +{ + 0x0020, // 0137 5F 95 _ Blank + 0x2666, // 0140 60 96 ` Diamond + 0x2592, // 0141 61 97 a Checkerboard + 0x2409, // 0142 62 98 b Horizontal Tab + 0x240C, // 0143 63 99 c Form Feed + 0x240D, // 0144 64 100 d Carriage Return + 0x240A, // 0145 65 101 e Line Feed + 0x00B0, // 0146 66 102 f Degree Symbol + 0x00B1, // 0147 67 103 g Plus/Minus + 0x2424, // 0150 68 104 h New Line + 0x240B, // 0151 69 105 i Vertical Tab + 0x2518, // 0152 6A 106 j Lower-right corner + 0x2510, // 0153 6B 107 k Upper-right corner + 0x250C, // 0154 6C 108 l Upper-left corner + 0x2514, // 0155 6D 109 m Lower-left corner + 0x253C, // 0156 6E 110 n Crossing Lines + 0x00AF, // 0157 6F 111 o Horizontal Line - Scan 1 + 0x0070, // 0160 70 112 p Horizontal Line - Scan 3 (No translation) + 0x2500, // 0161 71 113 q Horizontal Line - Scan 5 + 0x0072, // 0162 72 114 r Horizontal Line - Scan 7 (No translation) + 0x005F, // 0163 73 115 s Horizontal Line - Scan 9 + 0x251C, // 0164 74 116 t Left "T" + 0x2524, // 0165 75 117 u Right "T" + 0x2534, // 0166 76 118 v Bottom "T" + 0x252C, // 0167 77 119 w Top "T" + 0x2502, // 0170 78 120 x | Vertical bar + 0x2264, // 0171 79 121 y Less than or equal to + 0x2265, // 0172 7A 122 z Greater than or equal to + 0x03C0, // 0173 7B 123 { Pi + 0x2260, // 0174 7C 124 | Not equal to + 0x00A3, // 0175 7D 125 } UK Pound Sign + 0x00B7 // 0176 7E 126 ~ Centered dot +}; + +wchar_t CAnsiTerm::s_OemToUnicode[256] = +{ + 0x2007, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, // 00-07 + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, // 08-0F + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, // 10-17 + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, // 18-1F + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20-27 + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, // 28-2F + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30-37 + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, // 38-3F + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40-47 + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // 48-4F + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50-57 + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, // 58-5F + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60-67 + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // 68-6F + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70-77 + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, // 78-7F + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, // 80-87 + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, // 88-8F + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, // 90-97 + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, // 98-9F + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, // A0-A7 + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, // A8-AF + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, // B0-B7 + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, // B8-BF + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, // C0-C7 + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, // C8-CF + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, // D0-D7 + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, // D8-DF + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, // E0-E7 + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, // E8-EF + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, // F0-F7 + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 // F8-FF +}; + +COLORREF CAnsiTerm::s_ColorTable[kColorTableSize] = +{ + RGB(0, 0, 0), + RGB(0, 0, 128), + RGB(0, 128, 0), + RGB(0, 128, 128), + RGB(128, 0, 0), + RGB(128, 0, 128), + RGB(128, 128, 0), + RGB(192, 192, 192), + RGB(128, 128, 128), + RGB(0, 0, 255), + RGB(0, 255, 0), + RGB(0, 255, 255), + RGB(255, 0, 0), + RGB(255, 0, 255), + RGB(255, 255, 0), + RGB(255, 255, 255) +}; + +CAnsiTerm::PFN_GetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnGetConsoleScreenBufferInfoEx; +CAnsiTerm::PFN_SetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnSetConsoleScreenBufferInfoEx; + +CAnsiTerm::CAnsiTerm(void) +{ + m_hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleMode(m_hConsole, &m_dwOrigConsoleMode); + + SetConsoleMode(m_hConsole, ENABLE_PROCESSED_OUTPUT); + + CONSOLE_CURSOR_INFO cursorInfo; + + GetConsoleCursorInfo(m_hConsole, &cursorInfo); + + m_dwOrigCursorSize = cursorInfo.dwSize; + + WindowSizeChanged(true); +} + +CAnsiTerm::~CAnsiTerm(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { m_dwOrigCursorSize, TRUE }; + + SetConsoleCursorInfo(m_hConsole, &cursorInfo); + + SetConsoleMode(m_hConsole, m_dwOrigConsoleMode); + + SetConsoleTextAttribute(m_hConsole, m_wOrigConsoleAttribute); + + if (m_bResetColorTable) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + memcpy(consoleInfo.ColorTable, m_OrigColorTable, kColorTableSize * sizeof(consoleInfo.ColorTable[0])); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_wOrigConsoleAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + + CloseHandle(m_hConsole); +} + +void +CAnsiTerm::WindowSizeChanged(bool bInitial) +{ + WORD wCurrentAttribute; + COORD dwCurrentCursorPosition; + + if (bInitial) + { + HMODULE hKernel32 = GetModuleHandle("kernel32"); + + if (hKernel32 != NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = (PFN_GetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "GetConsoleScreenBufferInfoEx"); + s_pfnSetConsoleScreenBufferInfoEx = (PFN_SetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "SetConsoleScreenBufferInfoEx"); + + if (s_pfnGetConsoleScreenBufferInfoEx == NULL || s_pfnSetConsoleScreenBufferInfoEx == NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = NULL; + s_pfnSetConsoleScreenBufferInfoEx = NULL; + } + } + + m_bResetColorTable = false; + } + + if (s_pfnGetConsoleScreenBufferInfoEx != NULL) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + + if (bInitial) + { + m_bResetColorTable = memcmp(consoleInfo.ColorTable, s_ColorTable, sizeof(s_ColorTable)) != 0; + + if (m_bResetColorTable) + { + // The command prompt (cmd.exe) uses a nonstandard color table + // So we save it away and reset it to match the Console API documentation + size_t colorCopyLen = kColorTableSize * sizeof(consoleInfo.ColorTable[0]); + + memcpy(m_OrigColorTable, consoleInfo.ColorTable, colorCopyLen); + + memcpy(consoleInfo.ColorTable, s_ColorTable, colorCopyLen); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, kDefaultAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + } + } + else + { + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + + GetConsoleScreenBufferInfo(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + } + + m_WindowOrigin.X = 0; + m_WindowOrigin.Y = m_BufferSize.Y - m_WindowSize.Y; + + if (bInitial) + { + m_wOrigConsoleAttribute = wCurrentAttribute; + + SHORT nLines = dwCurrentCursorPosition.Y - m_WindowOrigin.Y; + + if (nLines != 0) + { + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', kDefaultAttribute }; + + if (nLines > 0) + { + rectSource.Top = nLines; + } + else + { + coordDest.Y -= nLines; + rectSource.Bottom += nLines; + } + + ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo); + } + } + + ResetTerm(); +} + +int +CAnsiTerm::ProcessInput(CAnsiTerm::KeyCode keyCode, unsigned char *pOutput, int iOutputSize) +{ + int iOutputLength = 0; + + if (pOutput == NULL || iOutputSize < 1) + { + return 0; + } + + if (!keyCode.bKeyDown) + { + return 0; + } + + if (VK_F1 <= keyCode.VirtualKeyCode && keyCode.VirtualKeyCode <= VK_F12) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = 'O'; + pOutput[iOutputLength++] = 'P' + keyCode.VirtualKeyCode - VK_F1; + } + else + if (keyCode.VirtualKeyCode == VK_UP || + keyCode.VirtualKeyCode == VK_DOWN || + keyCode.VirtualKeyCode == VK_RIGHT || + keyCode.VirtualKeyCode == VK_LEFT) + { + pOutput[iOutputLength++] = CH_ESC; + + if ((m_bCursorKeyMode && !keyCode.bControl) || + (!m_bCursorKeyMode && keyCode.bControl)) + { + pOutput[iOutputLength++] = 'O'; + } + else + { + pOutput[iOutputLength++] = '['; + } + + switch (keyCode.VirtualKeyCode) + { + case VK_UP: + pOutput[iOutputLength++] = 'A'; + break; + + case VK_DOWN: + pOutput[iOutputLength++] = 'B'; + break; + + case VK_RIGHT: + pOutput[iOutputLength++] = 'C'; + break; + + case VK_LEFT: + pOutput[iOutputLength++] = 'D'; + break; + } + } + else + if (keyCode.VirtualKeyCode == VK_HOME || + keyCode.VirtualKeyCode == VK_INSERT || + keyCode.VirtualKeyCode == VK_DELETE || + keyCode.VirtualKeyCode == VK_END || + keyCode.VirtualKeyCode == VK_PRIOR || + keyCode.VirtualKeyCode == VK_NEXT) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = '['; + + switch (keyCode.VirtualKeyCode) + { + case VK_HOME: + pOutput[iOutputLength++] = '1'; + break; + + case VK_INSERT: + pOutput[iOutputLength++] = '2'; + break; + + case VK_DELETE: + pOutput[iOutputLength++] = '3'; + break; + + case VK_END: + pOutput[iOutputLength++] = '4'; + break; + + case VK_PRIOR: + pOutput[iOutputLength++] = '5'; + break; + + case VK_NEXT: + pOutput[iOutputLength++] = '6'; + break; + } + + pOutput[iOutputLength++] = '~'; + } + else + if (keyCode.VirtualKeyCode == VK_RETURN) + { + pOutput[iOutputLength++] = CH_CR; + if (fCRLF == 1) + { + pOutput[iOutputLength++] = CH_LF; + } + } + else + if (keyCode.AsciiChar != '\0') + { + pOutput[iOutputLength++] = keyCode.AsciiChar; + } + + return iOutputLength; +} + +bool +CAnsiTerm::ProcessOutput(const unsigned char *szData, int iLength) +{ + const unsigned char *pEnd = &szData[iLength]; + + for (const unsigned char *pCurrent = szData; pCurrent < pEnd; pCurrent++) + { + if (*pCurrent < 0x20 || *pCurrent == 0x7F) + { + dbglog("ProcessOutput: control_ch = %02x\n",*pCurrent); + OutputText(); + + switch (*pCurrent) + { + case CH_NUL: + case CH_ENQ: + case CH_DEL: + // These are ignored + break; + + case CH_BEL: + MessageBeep(MB_ICONASTERISK); + break; + + case CH_BS: + ProcessBackspace(); + break; + + case CH_HT: + ProcessTab(); + break; + + case CH_LF: + case CH_VT: + case CH_FF: + ProcessLinefeed(m_bLineFeedNewLineMode); + break; + + case CH_CR: + ProcessReturn(); + break; + + case CH_SO: + m_SelectedCharset = CharsetG1; + break; + + case CH_SI: + m_SelectedCharset = CharsetG0; + break; + + case CH_XON: + // Not yet implemented + break; + + case CH_XOF: + // Not yet implemented + break; + +#if 0 + case CH_CAN: + case CH_SUB: + // Output error character + break; +#endif + + case CH_ESC: + m_State = DS_Escape; + break; + + default: + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + } + else + { + /* db b3 or b0 b3 */ + if (*pCurrent & 0x80) + dbglog("ProcessOutput: state=%d ch=%02x\n",m_State,*pCurrent); + switch (m_State) + { + case DS_Normal: + if (*pCurrent & 0x80) + { + // Could be start of a UTF-8 sequence or an ANSI extended character + + if ((*pCurrent & 0xE0) == 0xC0) + { + m_UTF8Size = 2; + } + else if ((*pCurrent & 0xF0) == 0xE0) + { + m_UTF8Size = 3; + } + else + { + // Not a UTF-8 lead character + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + m_UTF8Count = 1; + m_UTF8Buffer[0] = *pCurrent; + m_State = DS_UTF8; + break; + } + + if ((m_SelectedCharset == CharsetG0 && m_G0Charset == SpecialGraphicsCharset) || + (m_SelectedCharset == CharsetG1 && m_G1Charset == SpecialGraphicsCharset)) + { + if (kMinGraphicsChar <= *pCurrent && *pCurrent <= kMaxGraphicsChar) + { + AddOutputData(s_GraphicChars[*pCurrent - kMinGraphicsChar]); + } + else + { + AddOutputData(*pCurrent); + } + } + else + { + AddOutputData(*pCurrent); + } + break; + + case DS_UTF8: + if ((*pCurrent & 0xC0) != 0x80) + { + for (int index = 0; index < m_UTF8Count; index++) + { + AddOutputData(s_OemToUnicode[m_UTF8Buffer[index]]); + } + + if (*pCurrent & 0x80) + { + AddOutputData(s_OemToUnicode[*pCurrent]); + } + else + { + AddOutputData(*pCurrent); + } + m_State = DS_Normal; + } + else + { + m_UTF8Buffer[m_UTF8Count++] = *pCurrent; + + if (m_UTF8Count == m_UTF8Size) + { + wchar_t wchUTF16; + if (m_UTF8Size == 2) + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x1F) << 6) | (m_UTF8Buffer[1] & 0x3F); + } + else + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x0F) << 12) | ((m_UTF8Buffer[1] & 0x3F) << 6) | (m_UTF8Buffer[2] & 0x3F); + } + + AddOutputData(wchUTF16); + m_State = DS_Normal; + } + } + break; + + case DS_Escape: + for (int index = 0; s_CSITable[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSITable[index].chCode) + { + if (s_CSITable[index].dsNextState != DS_None) + { + m_State = s_CSITable[index].dsNextState; + m_Parameters[0] = 0; + m_ParameterCount = 0; + m_bParametersStart = true; + } + else + { + (this->*s_CSITable[index].pfnProcess)(); + m_State = DS_Normal; + } + break; + } + } + + if (m_State == DS_Escape) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(*pCurrent); + m_State = DS_Normal; + } + break; + + case DS_CSIParam: + if (m_bParametersStart) + { + m_bParametersStart = false; + + if (*pCurrent == '?') + { + m_bPrivateParameters = true; + break; + } + else + { + m_bPrivateParameters = false; + } + } + if ('0' <= *pCurrent && *pCurrent <= '9') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] *= 10; + m_Parameters[m_ParameterCount] += *pCurrent - '0'; + } + } + else if (*pCurrent == ';') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] = 0; + } + } + else + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + for (int index = 0; s_CSIFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSIFunction[index].chCode) + { + (this->*s_CSIFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + if (m_State != DS_Normal) + { + DisplayCSI(*pCurrent); + m_State = DS_Normal; + } + } + break; + + case DS_DECPrivate: + for (int index = 0; s_DECFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_DECFunction[index].chCode) + { + (this->*s_DECFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + + if (m_State != DS_Normal) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'#'); + AddOutputData(*pCurrent); + } + break; + + case DS_SelectG0: + ProcessSCSG0(*pCurrent); + m_State = DS_Normal; + break; + + case DS_SelectG1: + ProcessSCSG1(*pCurrent); + m_State = DS_Normal; + break; + + default: + dbglog("ProcessOutput: illegal m_State=%d\n",m_State); + assert(false); + break; + } + } + } + + OutputText(); + + return true; +} + +void +CAnsiTerm::DisplayCSI(char ch) +{ + char szParam[15]; + + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'['); + for (int idxParam = 0; idxParam < m_ParameterCount; idxParam++) + { + if (idxParam > 0) + { + AddOutputData(L';'); + } + + int iLenParam = sprintf(szParam, "%d", m_Parameters[idxParam]); + + for (int idxChar = 0; idxChar < iLenParam; idxChar++) + { + AddOutputData(szParam[idxChar]); + } + } + AddOutputData(ch); +} + +bool +CAnsiTerm::ResetTerm(void) +{ + m_State = DS_Normal; + + m_SelectedCharset = CharsetG0; + m_G0Charset = AsciiCharset; + m_G1Charset = SpecialGraphicsCharset; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + m_SavedCursor = m_Cursor; + + m_sTopMargin = 0; + m_sBottomMargin = m_WindowSize.Y - 1; + + m_Attribute = kDefaultAttribute; + + UpdateTextAttribute(); + + m_dwOutputCount = 0; + + // if (fCRLF == 1) + m_bLineFeedNewLineMode = true; /*was false*/ + m_bCursorKeyMode = false; + m_bAnsiMode = true; + m_bColumnMode = true; + m_bScrollingMode = false; + m_bScreenMode = false; + m_bOriginMode = false; + m_bAutoRepeatingMode = true; + m_bInterlaceMode = false; + m_bDisplayCursor = true; + m_bAutoWrapMode = true; /*default to wrap*/ + + EraseDisplay(EraseAll); + + SetCursorPosition(); + + DisplayCursor(); + + return true; +} + +bool +CAnsiTerm::DisplayCursor(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { 100, m_bDisplayCursor }; + + return SetConsoleCursorInfo(m_hConsole, &cursorInfo) != FALSE; +} + +bool +CAnsiTerm::UpdateTextAttribute(void) +{ + return SetConsoleTextAttribute(m_hConsole, m_Attribute) != FALSE; +} + +bool +CAnsiTerm::GetCursorPosition(void) +{ + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + + if (GetConsoleScreenBufferInfo(m_hConsole, &bufferInfo)) + { + m_Cursor = bufferInfo.dwCursorPosition; + m_Cursor.Y -= m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return true; + } + + return false; +} + +bool +CAnsiTerm::SetCursorPosition(void) +{ + COORD cursor = m_Cursor; + + cursor.Y += m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return SetConsoleCursorPosition(m_hConsole, cursor) != FALSE; +} + +bool +CAnsiTerm::ScrollDisplay(int n, bool bWindowOnly) +{ + SHORT nLines = (SHORT)n; + if (nLines == 0) + { + return true; + } + + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', m_Attribute }; + + if (nLines > 0) + { + if (bWindowOnly || m_sTopMargin > 0) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin + nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + else + { + rectSource.Top = nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + } + else + { + if (bWindowOnly) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin - nLines; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin + 1 + nLines; + } + else + { + coordDest.Y -= nLines; + } + + rectSource.Bottom += nLines; + } + + return ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo) != FALSE; +} + +bool +CAnsiTerm::EraseLine(EraseType eType) +{ + DWORD dwLength; + + COORD coordStart = m_WindowOrigin; + + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + dwLength = m_BufferSize.X - m_Cursor.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = m_Cursor.X + 1; + } + else + { + dwLength = m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +bool +CAnsiTerm::EraseDisplay(EraseType eType) +{ + COORD coordStart = m_WindowOrigin; + DWORD dwLength; + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X - m_Cursor.X; + } + else if (m_Cursor.Y < (m_WindowSize.Y - 1)) + { + coordStart.X = 0; + coordStart.Y += m_Cursor.Y + 1; + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0) - 1) * m_BufferSize.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X + m_Cursor.X; + } + else + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0) + 1) * m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X * m_WindowSize.Y; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +DWORD +CAnsiTerm::OutputText(void) +{ + if (m_dwOutputCount == 0) + { + return 0; + } + + DWORD dwTotalWritten = 0; + wchar_t * pwszCurrent = m_OutputBuffer; + DWORD dwLeftToWrite = m_dwOutputCount; + + while (dwLeftToWrite > 0) + { + DWORD dwWritten; + + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + + SetCursorPosition(); + + if (WriteConsoleW(m_hConsole, &m_OutputBuffer[m_dwOutputCount - 1], 1, &dwWritten, NULL)) + { + assert(dwWritten == 1); + } + + m_Cursor.X++; + dwTotalWritten += dwLeftToWrite; + break; + } + } + + DWORD dwPartialCount = min(dwLeftToWrite, (DWORD)(m_WindowSize.X - m_Cursor.X)); + + if (WriteConsoleW(m_hConsole, pwszCurrent, dwPartialCount, &dwWritten, NULL)) + { + assert(dwWritten == dwPartialCount); + } + else + { + DWORD dwError = GetLastError(); + } + + m_Cursor.X += (SHORT)dwPartialCount; + pwszCurrent += dwPartialCount; + dwTotalWritten += dwPartialCount; + dwLeftToWrite -= dwPartialCount; + } + + m_dwOutputCount = 0; + + return dwTotalWritten; +} + +bool +CAnsiTerm::ProcessBackspace(void) +{ + if (m_Cursor.X > 0) + { + if (m_Cursor.X < m_WindowSize.X) + { + m_Cursor.X--; + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + } + + return SetCursorPosition(); + } + return true; +} + +bool +CAnsiTerm::ProcessTab(void) +{ + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + return true; + } + } + + int newX = m_Cursor.X + 8; + + newX &= ~7; + + if (newX >= m_WindowSize.X) + { + newX = m_WindowSize.X - 1; + } + + int cntSpaces = newX - m_Cursor.X; + + for (int index = 0; index < cntSpaces; index++) + { + AddOutputData(L' '); + } + + return true; +} + +bool +CAnsiTerm::ProcessReverseLinefeed(void) +{ + if (m_Cursor.Y == 0) + { + ScrollDisplay(-1, true); + } + else + { + m_Cursor.Y--; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessLinefeed(bool bNewLine) +{ + if (bNewLine) + { + m_Cursor.X = 0; + } + + if (m_bOriginMode || (m_Cursor.Y >= m_sTopMargin && m_Cursor.Y <= m_sBottomMargin)) + { + if (m_Cursor.Y >= (m_sBottomMargin - m_sTopMargin)) + { + ScrollDisplay(1, false); + m_Cursor.Y = m_sBottomMargin; + } + else + { + m_Cursor.Y++; + } + } + else if (m_Cursor.Y < m_sBottomMargin) + { + m_Cursor.Y++; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessReturn(void) +{ + m_Cursor.X = 0; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDECALN(void) +{ + // Fill the display with 'E' for adjusting the CRT on a VT100 - Ignore it + return true; +} + +bool +CAnsiTerm::ProcessDECDHLB(void) +{ + // Double Height Line Bottom - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDHLT(void) +{ + // Double Height Line Top - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDWL(void) +{ + // Double Width Line - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECID(void) +{ + return ProcessDA(); +} + +bool +CAnsiTerm::ProcessDECKPAM(void) +{ + // Keypad Application Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECKPNM(void) +{ + // Keypad Numeric Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECLL(void) +{ + // Load LEDs - Not Supported + return true; +} + +bool +CAnsiTerm::ProcessDECRC(void) +{ + return ProcessRCP(); +} + +bool +CAnsiTerm::ProcessDECREQTPARM(void) +{ + // Request Terminal Parameters (Baud Rate, Parity, etc) - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECSC(void) +{ + return ProcessSCP(); +} + +bool +CAnsiTerm::ProcessDECSTBM(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + else + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[0] >= m_WindowSize.Y || + m_Parameters[1] >= m_WindowSize.Y || + m_Parameters[0] >= m_Parameters[1]) + { + return false; + } + + m_sTopMargin = (SHORT)m_Parameters[0]; + m_sBottomMargin = (SHORT)m_Parameters[1]; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + SetCursorPosition(); + + return true; +} + +bool +CAnsiTerm::ProcessDECSWL(void) +{ + // Single Width Line - Since Double Width Line isn't supported, this isn't necessary + return true; +} + +bool +CAnsiTerm::ProcessDECTST(void) +{ + // Perform Self Test - Not supported + return true; +} + +bool +CAnsiTerm::ProcessCUB(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X -= min(m_Cursor.X, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUD(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y += min((m_bOriginMode ? m_sBottomMargin : m_WindowSize.Y - 1) - m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUF(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X += min(m_WindowSize.X - m_Cursor.X - 1, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUP(void) +{ + return ProcessHVP(); +} + +bool +CAnsiTerm::ProcessCUU(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y -= min(m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDA(void) +{ + // Send Device Attributes - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDSR(void) +{ + // Send Device Status Request - Not supported + return true; +} + +bool +CAnsiTerm::ProcessED(void) +{ + return EraseDisplay((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessEL(void) +{ + return EraseLine((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessHTS(void) +{ + // Soft Tab Set - Not implemented yet + return true; +} + +bool +CAnsiTerm::ProcessHVP(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = 0; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + } + + if (m_bOriginMode) + { + if (m_Parameters[0] >= (m_sBottomMargin - m_sTopMargin + 1)) + { + m_Parameters[0] = m_sBottomMargin - m_sTopMargin; + } + } + else + { + if (m_Parameters[0] >= m_WindowSize.Y) + { + m_Parameters[0] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[1] >= m_WindowSize.X) + { + m_Parameters[1] = m_WindowSize.X - 1; + } + + m_Cursor.Y = (SHORT)m_Parameters[0]; + m_Cursor.X = (SHORT)m_Parameters[1]; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessIND(void) +{ + return ProcessLinefeed(false); +} + +bool +CAnsiTerm::ProcessNEL(void) +{ + return ProcessLinefeed(true); +} + +bool +CAnsiTerm::ProcessRCP(void) +{ + m_Cursor = m_SavedCursor; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessRI(void) +{ + return ProcessReverseLinefeed(); +} + +bool +CAnsiTerm::ProcessRIS(void) +{ + return ResetTerm(); +} + +bool +CAnsiTerm::ProcessRM(void) +{ + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = false; + break; + case DECANM: + m_bAnsiMode = false; + break; + case DECCOLM: + m_bColumnMode = false; + break; + case DECSCLM: + m_bScrollingMode = false; + break; + case DECSCNM: + m_bScreenMode = false; + break; + case DECOM: + m_bOriginMode = false; + m_Cursor.X = 0; + m_Cursor.Y = 0; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = false; + break; + case DECARM: + m_bAutoRepeatingMode = false; + break; + case DECINLM: + m_bInterlaceMode = false; + break; + case DECTCEM: + m_bDisplayCursor = false; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 20: m_bLineFeedNewLineMode = false; break; // LNM + default: assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessSCP(void) +{ + m_SavedCursor = m_Cursor; + return true; +} + +bool +CAnsiTerm::ProcessSCSG0(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G0Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G0Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSCSG1(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G1Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G1Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSGR(void) +{ + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + m_Attribute = kDefaultAttribute; + break; + + case 1: + m_Attribute |= FOREGROUND_INTENSITY; + break; + + case 4: + m_Attribute |= COMMON_LVB_UNDERSCORE; + break; + + case 5: + // Blinking isn't supported + break; + + case 7: + m_Attribute |= COMMON_LVB_REVERSE_VIDEO; + break; + + case 22: + m_Attribute &= ~FOREGROUND_INTENSITY; + break; + + case 24: + m_Attribute &= ~COMMON_LVB_UNDERSCORE; + break; + + case 25: + // Blinking isn't supported + break; + + case 27: + m_Attribute &= ~COMMON_LVB_REVERSE_VIDEO; + break; + + case 30: // Black text + m_Attribute &= ~(FOREGROUND_INTENSITY | COMMON_LVB_UNDERSCORE | + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + break; + + case 31: // Red text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED; + break; + + case 32: // Green text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN; + break; + + case 33: // Yellow text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + + case 34: // Blue text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_BLUE; + break; + + case 35: // Magenta text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + + case 36: // Cyan text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 37: // White text + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 40: // Black background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + break; + + case 41: // Red background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED; + break; + + case 42: // Green background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN; + break; + + case 43: // Yellow background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + + case 44: // Blue background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_BLUE; + break; + + case 45: // Magenta background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + + case 46: // Cyan background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + case 47: // White background + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + default: + assert(false); + break; + } + } + + UpdateTextAttribute(); + + return true; +} + +bool +CAnsiTerm::ProcessSM(void) +{ + + dbglog("ProcessSM: start, priv=%d param0=%d cnt=%d\n", + m_bPrivateParameters,m_Parameters[0],m_ParameterCount); + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = true; + break; + case DECANM: + m_bAnsiMode = true; + break; + case DECCOLM: + m_bColumnMode = true; + break; + case DECSCLM: + m_bScrollingMode = true; + break; + case DECSCNM: + m_bScreenMode = true; + break; + case DECOM: + m_bOriginMode = true; + m_Cursor.X = 0; + m_Cursor.Y = 0; + m_SavedCursor = m_Cursor; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = true; + break; + case DECARM: + m_bAutoRepeatingMode = true; + break; + case DECINLM: + m_bInterlaceMode = true; + break; + case DECTCEM: + m_bDisplayCursor = true; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 20: m_bLineFeedNewLineMode = true; break; // LNM + default: + dbglog("ProcessSM: param %d != 20\n",m_Parameters[0]); + assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessTBC(void) +{ + // Soft Tab Clear - Not implemented yet + return true; +} + +static CAnsiTerm *g_pDisplay; + +typedef unsigned char uchar; + +extern "C" +{ + +void console_open(char fdebugcmd) +{ + g_pDisplay = new CAnsiTerm(); +} + +void console_close(void) +{ + delete g_pDisplay; + g_pDisplay = NULL; +} + +int console_in(DWORD keydata, uchar *pdata, int len) +{ + if (keydata == ~0) + { + g_pDisplay->WindowSizeChanged(false); + return 0; + } + + return g_pDisplay->ProcessInput(*(CAnsiTerm::KeyCode *)&keydata, pdata, len); +} + +void console_out(uchar *pdata, int len) +{ + if (len > 0) + { + g_pDisplay->ProcessOutput(pdata, len); + } +} + +} -- cgit v1.2.3