///////////////////////////////////////////////////////////////////////////// // Copyright (C) 2001-2004 by Marko Bozikovic // All rights reserved // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Send bug reports, bug fixes, enhancements, requests, flames, etc., and // I'll try to keep a version up to date. I can be reached as follows: // marko.bozikovic@alterbox.net // bozho@kset.org ///////////////////////////////////////////////////////////////////////////// #ifdef UNICODE #error "Unicode defined" #endif ///////////////////////////////////////////////////////////////////////////// // Console.cpp - console class implementation #include "builddefines.h" #undef CINTERFACE //#include "stdafx.h" //#include #include #include #include #include #include #include #include #include #include "resource.h" #include "FileStream.h" //#include "ComBSTROut.h" //#include "ComVariantOut.h" #include "Cursors.h" #include "Dialogs.h" #include "Console.h" #ifdef _DEBUG //#define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern HINSTANCE ghInstance; ///////////////////////////////////////////////////////////////////////////// // Console class ///////////////////////////////////////////////////////////////////////////// // Console window class names const TCHAR Console::m_szConsoleClass[] = _T("Console Main Command Window"); const TCHAR Console::m_szHiddenParentClass[] = _T("Console Invisible Parent Window"); ///////////////////////////////////////////////////////////////////////////// // win console window title const tstring Console::m_strWinConsoleTitle(_T("Console Command Window")); ///////////////////////////////////////////////////////////////////////////// // ctor/dtor Console::Console(LPCTSTR pszConfigFile, LPCTSTR pszShellCmdLine, LPCTSTR pszConsoleTitle, LPCTSTR pszReloadNewConfig) : m_hWnd(NULL) , m_bInitializing(TRUE) , m_bReloading(FALSE) , m_strConfigEditor(_T("notepad.exe")) , m_strConfigEditorParams(_T("")) , m_strShell(_T("")) , m_strShellCmdLine(pszShellCmdLine) , m_hwndInvisParent(NULL) , m_hdcConsole(NULL) , m_hdcWindow(NULL) , m_hbmpConsole(NULL) , m_hbmpConsoleOld(NULL) , m_hbmpWindow(NULL) , m_hbmpWindowOld(NULL) , m_hBkBrush(NULL) , m_dwMasterRepaintInt(500) , m_dwChangeRepaintInt(50) , m_strIconFilename(_T("")) , m_hSmallIcon(NULL) , m_hBigIcon(NULL) , m_hPopupMenu(NULL) , m_hSysMenu(NULL) , m_hConfigFilesMenu(NULL) , m_bPopupMenuDisabled(FALSE) , m_strWindowTitleDefault(_tcslen(pszConsoleTitle) == 0 ? _T("console") : pszConsoleTitle) , m_strWindowTitle(m_strWindowTitleDefault) , m_strWindowTitleCurrent(m_strWindowTitleDefault) , m_strFontName(_T("Courier New")) , m_dwFontSize(10) , m_bBold(FALSE) , m_bItalic(FALSE) , m_bUseFontColor(FALSE) , m_crFontColor(RGB(0, 0, 0)) , m_hFont(NULL) , m_hFontOld(NULL) , m_nX(0) , m_nY(0) , m_nInsideBorder(0) , m_nWindowWidth(0) , m_nWindowHeight(0) , m_nXBorderSize(5) , m_nYBorderSize(5) , m_nCaptionSize(0) , m_nClientWidth(0) , m_nClientHeight(0) , m_nCharHeight(0) , m_nCharWidth(0) , m_dwWindowBorder(BORDER_REGULAR) , m_bShowScrollbar(TRUE) , m_nScrollbarStyle(FSB_REGULAR_MODE) , m_crScrollbarColor(::GetSysColor(COLOR_3DHILIGHT)) , m_nScrollbarWidth(::GetSystemMetrics(SM_CXVSCROLL)) , m_nScrollbarButtonHeight(::GetSystemMetrics(SM_CYVSCROLL)) , m_nScrollbarThunmbHeight(::GetSystemMetrics(SM_CYVTHUMB)) , m_dwTaskbarButton(TASKBAR_BUTTON_NORMAL) , m_bMouseDragable(TRUE) , m_nSnapDst(10) , m_dwDocked(DOCK_NONE) , m_dwOriginalZOrder(Z_ORDER_REGULAR) , m_dwCurrentZOrder(Z_ORDER_REGULAR) , m_dwTransparency(TRANSPARENCY_NONE) , m_byAlpha(150) , m_byInactiveAlpha(150) , m_crBackground(RGB(0, 0, 0)) , m_crConsoleBackground(RGB(0, 0, 0)) , m_bTintSet(FALSE) , m_byTintOpacity(50) , m_byTintR(0) , m_byTintG(0) , m_byTintB(0) , m_bBitmapBackground(FALSE) , m_strBackgroundFile(_T("")) , m_hdcBackground(NULL) , m_hbmpBackground(NULL) , m_hbmpBackgroundOld(NULL) , m_dwBackgroundStyle(BACKGROUND_STYLE_RESIZE) , m_bRelativeBackground(FALSE) , m_bExtendBackground(FALSE) , m_nBackgroundOffsetX(0) , m_nBackgroundOffsetY(0) , m_bHideWindow(FALSE) , m_bHideConsole(TRUE) , m_dwHideConsoleTimeout(0) , m_bStartMinimized(FALSE) , m_dwCursorStyle(CURSOR_STYLE_CONSOLE) , m_crCursorColor(RGB(255, 255, 255)) , m_bCursorVisible(TRUE) , m_pCursor(NULL) , m_hWndConsole(NULL) , m_hStdOut(NULL) , m_hStdOutFresh(NULL) , m_hQuitEvent(NULL) , m_hConsoleProcess(NULL) , m_hMonitorThread(NULL) , m_dwRows(50) , m_dwColumns(80) , m_dwBufferRows(500) , m_bUseTextBuffer(TRUE) , m_nTextSelection(TEXT_SELECTION_NONE) , m_bCopyOnSelect(FALSE) , m_bInverseShift(FALSE) , m_hdcSelection(NULL) , m_hbmpSelection(NULL) , m_hbmpSelectionOld(NULL) , m_hbrushSelection(::CreateSolidBrush(RGB(0xff, 0xff, 0xff))) , m_pScreenBuffer(NULL) , m_pScreenBufferNew(NULL) , m_nTextColor(15) , m_nTextBgColor(0) { #if 0 m_strConfigFile = GetFullFilename(pszConfigFile); if (!_tcsicmp(pszReloadNewConfig, _T("yes"))) { m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_YES; } else if (!_tcsicmp(pszReloadNewConfig, _T("no"))) { m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_NO; } else { m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_PROMPT; } m_dwReloadNewConfig = m_dwReloadNewConfigDefault; #endif m_mouseCursorOffset.x = 0; m_mouseCursorOffset.y = 0; m_coordSelOrigin.X = 0; m_coordSelOrigin.Y = 0; ::ZeroMemory(&m_rectSelection, sizeof(RECT)); #if 0 // get Console.exe directory TCHAR szPathName[MAX_PATH]; ::ZeroMemory(szPathName, sizeof(szPathName)); ::GetModuleFileName(ghInstance, szPathName, MAX_PATH); tstring strExeDir(szPathName); strExeDir = strExeDir.substr(0, strExeDir.rfind(_T("\\"))); strExeDir += TCHAR('\\'); // if no config file is given, get console.xml from the startup directory if (m_strConfigFile.length() == 0) { m_strConfigFile = strExeDir + tstring(_T("console.xml")); } // get readme filename m_strReadmeFile = strExeDir + tstring(_T("Readme.txt")); #endif ::ZeroMemory(&m_csbiCursor, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); ::ZeroMemory(&m_csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); SetDefaultConsoleColors(); AllocateBuffer(); // Set the stdout and stderr to this window HANDLE myOut; ::CreatePipe( &m_hStdOut, &myOut, NULL, 0); ::SetStdHandle( STD_OUTPUT_HANDLE, myOut); ::SetStdHandle( STD_ERROR_HANDLE, myOut); int hConHandle = _open_osfhandle((long)myOut, _O_BINARY); //_O_WTEXT); FILE *fp = _fdopen( hConHandle, "w" ); *stdout = *fp; *stderr = *fp; setvbuf( stdout, NULL, _IONBF, 0 ); // create text monitor thread DWORD dwThreadID; m_hMonitorThread = ::CreateThread(NULL, 0, Console::MonitorThreadStatic, this, CREATE_SUSPENDED, &dwThreadID); ::ResumeThread(m_hMonitorThread); } Console::~Console() { delete[] m_pScreenBuffer; delete[] m_pScreenBufferNew; if (m_hSmallIcon) ::DestroyIcon(m_hSmallIcon); if (m_hBigIcon) ::DestroyIcon(m_hBigIcon); // ::CloseHandle(m_hConsoleProcess); // ::CloseHandle(m_hQuitEvent); // shutdown console process // ::CloseHandle(m_hStdOut); // ::CloseHandle(m_hStdOutFresh); // if (m_hWndConsole) ::SendMessage(m_hWndConsole, WM_CLOSE, 0, 0); // ::FreeConsole(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Public methods ///////////////////////////////////////////////////////////////////////////// // creates and shows Console window BOOL Console::Create(HWND notify) { m_notifyhWnd = notify; if (m_hWnd) { ::ShowWindow( m_hWnd, SW_SHOW); return TRUE; } if (!GetOptions()) return FALSE; if (!RegisterWindowClasses()) return FALSE; if (!CreateConsoleWindow()) return FALSE; // create window DC HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0); m_hdcConsole = ::CreateCompatibleDC(hdcDesktop); m_hdcWindow = ::CreateCompatibleDC(hdcDesktop); ::ReleaseDC(m_hWnd, hdcDesktop); // create selection DC m_hdcSelection = ::CreateCompatibleDC(m_hdcWindow); if (!SetupMenus()) return FALSE; CreateNewFont(); CreateNewBrush(); // SetWindowTransparency(); SetWindowIcons(); GetTextSize(); GetBordersDimensions(); CreateCursor(); // now we can start the monitor thread StartShellProcess(); // set the long repaint timer if (m_dwMasterRepaintInt) ::SetTimer(m_hWnd, TIMER_REPAINT_MASTER, m_dwMasterRepaintInt, NULL); m_bInitializing = FALSE; // register for files/folders drag-n-drop ::DragAcceptFiles(m_hWnd, TRUE); RefreshScreenBuffer(); ::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns); RepaintWindow(); ::UpdateWindow(m_hWnd); if (m_bStartMinimized) { if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) { m_bHideWindow = TRUE; } else { ::ShowWindow(m_hWnd, SW_MINIMIZE); } } else { ::ShowWindow(m_hWnd, SW_SHOW); } ::SetForegroundWindow(m_hWnd); return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Message handlers ///////////////////////////////////////////////////////////////////////////// void Console::OnDestroy() { if (!m_bInitializing) { ::SetEvent(m_hQuitEvent); ::WaitForSingleObject(m_hMonitorThread, 2000); ::CloseHandle(m_hMonitorThread); // kill timers ::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE); if (m_dwMasterRepaintInt) ::KillTimer(m_hWnd, TIMER_REPAINT_MASTER); DestroyCursor(); // cleanup graphics objects if (m_hFontOld) ::SelectObject(m_hdcConsole, m_hFontOld); if (m_hFont) ::DeleteObject(m_hFont); if (m_hBkBrush) ::DeleteObject(m_hBkBrush); if (m_hbmpConsoleOld) ::SelectObject(m_hdcConsole, m_hbmpConsoleOld); if (m_hbmpConsole) ::DeleteObject(m_hbmpConsole); if (m_hbmpWindowOld) ::SelectObject(m_hdcWindow, m_hbmpWindowOld); if (m_hbmpWindow) ::DeleteObject(m_hbmpWindow); if (m_hbmpBackgroundOld) ::SelectObject(m_hdcBackground, m_hbmpBackgroundOld); if (m_hbmpBackground) ::DeleteObject(m_hbmpBackground); if (m_hdcBackground) ::DeleteDC(m_hdcBackground); if (m_hbmpSelectionOld) ::SelectObject(m_hdcSelection, m_hbmpSelectionOld); if (m_hbmpSelection)::DeleteObject(m_hbmpSelection); if (m_hdcSelection) ::DeleteDC(m_hdcSelection); if (m_hbrushSelection) ::DeleteObject(m_hbrushSelection); ::DestroyMenu(m_hConfigFilesMenu); ::DestroyMenu(m_hPopupMenu); SetTrayIcon(NIM_DELETE); ::DeleteDC(m_hdcConsole); ::DeleteDC(m_hdcWindow); ::PostQuitMessage(0); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnNcDestroy() { if (!m_bInitializing) delete this; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnPaint() { PAINTSTRUCT paintStruct; HDC hdc = ::BeginPaint(m_hWnd, &paintStruct); if (!m_nTextSelection) { // if there's no selection, just blit console image ::BitBlt( hdc, paintStruct.rcPaint.left, paintStruct.rcPaint.top, paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1, paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1, m_hdcConsole, paintStruct.rcPaint.left, paintStruct.rcPaint.top, SRCCOPY); } else { // there's a text selection, first compose the image in an off-screen // buffer, and then blit it ::BitBlt( m_hdcWindow, paintStruct.rcPaint.left, paintStruct.rcPaint.top, paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1, paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1, m_hdcConsole, paintStruct.rcPaint.left, paintStruct.rcPaint.top, SRCCOPY); ::BitBlt( m_hdcWindow, m_rectSelection.left, m_rectSelection.top, m_rectSelection.right - m_rectSelection.left, m_rectSelection.bottom - m_rectSelection.top, m_hdcSelection, 0, 0, SRCINVERT); ::BitBlt( hdc, paintStruct.rcPaint.left, paintStruct.rcPaint.top, paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1, paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1, m_hdcWindow, paintStruct.rcPaint.left, paintStruct.rcPaint.top, SRCCOPY); } ::EndPaint(m_hWnd, &paintStruct); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnPaintTimer() { ::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE); RefreshStdOut(); RefreshScreenBuffer(); if (GetChangeRate() > 15) { ::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns); RepaintWindow(); } else { RepaintWindowChanges(); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnCursorTimer() { if (m_pCursor) { m_pCursor->PrepareNext(); DrawCursor(); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnWindowPosChanging(WINDOWPOS* lpWndPos) { if (!(lpWndPos->flags & SWP_NOMOVE)) { if (m_nSnapDst >= 0) { // we'll snap Console window to the desktop edges RECT rectDesktop; GetDesktopRect(rectDesktop); m_dwDocked = DOCK_NONE; DWORD dwLeftRight = 0; DWORD dwTopBottom = 0; // now, see if we're close to the edges if (lpWndPos->x <= rectDesktop.left + m_nSnapDst) { lpWndPos->x = rectDesktop.left; dwLeftRight = 1; } if (lpWndPos->x >= rectDesktop.right - m_nWindowWidth - m_nSnapDst) { lpWndPos->x = rectDesktop.right - m_nWindowWidth; dwLeftRight = 2; } if (lpWndPos->y <= rectDesktop.top + m_nSnapDst) { lpWndPos->y = rectDesktop.top; dwTopBottom = 1; } if (lpWndPos->y >= rectDesktop.bottom - m_nWindowHeight - m_nSnapDst) { lpWndPos->y = rectDesktop.bottom - m_nWindowHeight; dwTopBottom = 2; } // now, see if the window is docked if (dwLeftRight == 1) { // left edge if (dwTopBottom == 1) { // top left m_dwDocked = DOCK_TOP_LEFT; } else if (dwTopBottom == 2) { // bottom left m_dwDocked = DOCK_BOTTOM_LEFT; } } else if (dwLeftRight == 2) { // right edge if (dwTopBottom == 1) { // top right m_dwDocked = DOCK_TOP_RIGHT; } else if (dwTopBottom == 2) { // bottom right m_dwDocked = DOCK_BOTTOM_RIGHT; } } } m_nX = lpWndPos->x; m_nY = lpWndPos->y; // TRACE(_T("Win pos: %ix%i\n"), m_nX, m_nY); // we need to repaint for relative backgrounds // if (m_bRelativeBackground && !m_bInitializing) RepaintWindow(); } if (m_dwCurrentZOrder == Z_ORDER_ONBOTTOM) lpWndPos->hwndInsertAfter = HWND_BOTTOM; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnActivateApp(BOOL bActivate, DWORD dwFlags) { if (m_pCursor) { m_pCursor->SetState(bActivate); DrawCursor(); } #if 0 if ((m_dwTransparency == TRANSPARENCY_ALPHA) && (m_byInactiveAlpha > 0)) { if (bActivate) { g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byAlpha, LWA_ALPHA); } else { g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byInactiveAlpha, LWA_ALPHA); } } #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnVScroll(WPARAM wParam) { // TRACE(_T("VScroll\n")); int nCurrentPos = ::GetScrollPos(m_hWnd, SB_VERT); int nDelta = 0; switch(LOWORD (wParam)) { case SB_PAGEUP: nDelta = -5; break; case SB_PAGEDOWN: nDelta = 5; break; case SB_LINEUP: nDelta = -1; break; case SB_LINEDOWN: nDelta = 1; break; case SB_THUMBTRACK: nDelta = HIWORD(wParam) - nCurrentPos; break; case SB_ENDSCROLL: return; default: return; } if ((nDelta = max(-nCurrentPos, min(nDelta, (int)(m_dwBufferRows-m_dwRows) - nCurrentPos))) != 0) { nCurrentPos += nDelta; SMALL_RECT sr; sr.Top = (short) nCurrentPos; // sr.Bottom = nDelta; sr.Left = sr.Right = 0; m_csbiConsole.srWindow = sr; // ::SetConsoleWindowInfo(m_hStdOutFresh, FALSE, &sr); SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = nCurrentPos; ::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE); // this seems to work/look much better than direct repainting... ::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnInputLangChangeRequest(WPARAM wParam, LPARAM lParam) { ::PostMessage(m_hWndConsole, WM_INPUTLANGCHANGEREQUEST, wParam, lParam); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnLButtonDown(UINT uiFlags, POINTS points) { #if 0 RECT windowRect; ::GetCursorPos(&m_mouseCursorOffset); ::GetWindowRect(m_hWnd, &windowRect); m_mouseCursorOffset.x -= windowRect.left; m_mouseCursorOffset.y -= windowRect.top; if (!m_bMouseDragable || (m_bInverseShift == !(uiFlags & MK_SHIFT))) { if (m_nCharWidth) { if (m_nTextSelection == TEXT_SELECTION_SELECTED) return; // fixed-width characters // start copy text selection ::SetCapture(m_hWnd); if (!m_nTextSelection) { RECT rect; rect.left = 0; rect.top = 0; rect.right = m_nClientWidth; rect.bottom = m_nClientHeight; ::FillRect(m_hdcSelection, &rect, m_hbrushSelection); } m_nTextSelection = TEXT_SELECTION_SELECTING; m_coordSelOrigin.X = min(max(points.x - m_nInsideBorder, 0) / m_nCharWidth, m_dwColumns-1); m_coordSelOrigin.Y = min(max(points.y - m_nInsideBorder, 0) / m_nCharHeight, m_dwRows-1); m_rectSelection.left = m_rectSelection.right = m_coordSelOrigin.X * m_nCharWidth + m_nInsideBorder; m_rectSelection.top = m_rectSelection.bottom = m_coordSelOrigin.Y * m_nCharHeight + m_nInsideBorder; TRACE(_T("Starting point: %ix%i\n"), m_coordSelOrigin.X, m_coordSelOrigin.Y); } } else { if (m_nTextSelection) { return; } else if (m_bMouseDragable) { // start to drag window ::SetCapture(m_hWnd); } } #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnLButtonUp(UINT uiFlags, POINTS points) { if ((m_nTextSelection == TEXT_SELECTION_SELECTED) || // X Windows select/copy style ((m_nTextSelection == TEXT_SELECTION_SELECTING) && (m_bCopyOnSelect))) { // if the user clicked inside the selection rectangle, copy data if ((points.x >= m_rectSelection.left) && (points.x <= m_rectSelection.right) && (points.y >= m_rectSelection.top) && (points.y <= m_rectSelection.bottom)) { CopyTextToClipboard(); } if (m_bCopyOnSelect) ::ReleaseCapture(); ClearSelection(); } else if (m_nTextSelection == TEXT_SELECTION_SELECTING) { if ((m_rectSelection.left == m_rectSelection.right) && (m_rectSelection.top == m_rectSelection.bottom)) { m_nTextSelection = TEXT_SELECTION_NONE; } else { m_nTextSelection = TEXT_SELECTION_SELECTED; } ::ReleaseCapture(); } else if (m_bMouseDragable) { // end window drag ::ReleaseCapture(); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnLButtonDblClick(UINT uiFlags, POINTS points) { // ToggleWindowOnTop(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnRButtonUp(UINT uiFlags, POINTS points) { if (uiFlags & MK_SHIFT) { PasteClipoardText(); } else { if (m_bPopupMenuDisabled) return; POINT point; point.x = points.x; point.y = points.y; ::ClientToScreen(m_hWnd, &point); HMENU hPopup = ::GetSubMenu(m_hPopupMenu, 0); // show popup menu ::TrackPopupMenu(hPopup, 0, point.x, point.y, 0, m_hWnd, NULL); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnMButtonDown(UINT uiFlags, POINTS points) { PasteClipoardText(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnMouseMove(UINT uiFlags, POINTS points) { #if 0 RECT windowRect; int deltaX, deltaY; POINT point; if (uiFlags & MK_LBUTTON) { ::GetWindowRect(m_hWnd, &windowRect); point.x = points.x; point.y = points.y; ::ClientToScreen(m_hWnd, &point); deltaX = point.x - windowRect.left - m_mouseCursorOffset.x; deltaY = point.y - windowRect.top - m_mouseCursorOffset.y; if (deltaX | deltaY) { // TRACE(_T("m_nTextSelection: %i, Delta X: %i Delta Y: %i\n"), m_nTextSelection, deltaX, deltaY); if (m_nTextSelection) { if ((!m_bMouseDragable) || (m_bInverseShift == !(uiFlags & MK_SHIFT))) { // some text has been selected, just return if (m_nTextSelection == TEXT_SELECTION_SELECTED) return; // selecting text for copy/paste COORD coordSel; ::InvalidateRect(m_hWnd, &m_rectSelection, FALSE); coordSel.X = min(max(points.x - m_nInsideBorder, 0) / m_nCharWidth, m_dwColumns-1); coordSel.Y = min(max(points.y - m_nInsideBorder, 0) / m_nCharHeight, m_dwRows-1); // TRACE(_T("End point: %ix%i\n"), coordSel.X, coordSel.Y); if (coordSel.X >= m_coordSelOrigin.X) { m_rectSelection.left = m_coordSelOrigin.X * m_nCharWidth + m_nInsideBorder; m_rectSelection.right = (coordSel.X + 1) * m_nCharWidth + m_nInsideBorder; } else { m_rectSelection.left = coordSel.X * m_nCharWidth + m_nInsideBorder; m_rectSelection.right = (m_coordSelOrigin.X + 1) * m_nCharWidth + m_nInsideBorder; } if (coordSel.Y >= m_coordSelOrigin.Y) { m_rectSelection.top = m_coordSelOrigin.Y * m_nCharHeight + m_nInsideBorder; m_rectSelection.bottom = (coordSel.Y + 1) * m_nCharHeight + m_nInsideBorder; } else { m_rectSelection.top = coordSel.Y * m_nCharHeight + m_nInsideBorder; m_rectSelection.bottom = (m_coordSelOrigin.Y + 1) * m_nCharHeight + m_nInsideBorder; } // TRACE(_T("Selection rect: %i,%i x %i,%i\n"), m_rectSelection.left, m_rectSelection.top, m_rectSelection.right, m_rectSelection.bottom); ::InvalidateRect(m_hWnd, &m_rectSelection, FALSE); } } else if (m_bMouseDragable) { // moving the window HWND hwndZ; switch (m_dwCurrentZOrder) { case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break; case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break; case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break; } ::SetWindowPos( m_hWnd, hwndZ, windowRect.left + deltaX, windowRect.top + deltaY, 0, 0, SWP_NOSIZE); ::PostMessage(m_hWnd, WM_PAINT, 0, 0); } } } #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnChar(WORD myChar) { wchar_t text[16]; if (myChar == 8) { int l = Input.length(); if (l > 0) { wchar_t last = Input[ l - 1]; if (last == '\n') { return; } text[0] = 8; text[1] = L' '; text[2] = 8; text[3] = 0; Input.resize( l - 1); } else { return; } } else if (myChar == '\r') { text[0] = '\n'; text[1] = '\r'; text[2] = 0; Input += '\n'; SendTextToConsole( text); SendMessage( m_notifyhWnd, WM_INPUTREADY, 0, (LPARAM) &Input); return; } else { text[0] = myChar; text[1] = 0; Input += text; } SendTextToConsole( text); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnSetCursor(WORD wHitTest, WORD wMouseMessage) { if (wHitTest == HTBORDER) { if (wMouseMessage == WM_LBUTTONDOWN) { if (m_bMouseDragable) { // start to drag window RECT windowRect; ::GetCursorPos(&m_mouseCursorOffset); ::GetWindowRect(m_hWnd, &windowRect); m_mouseCursorOffset.x -= windowRect.left; m_mouseCursorOffset.y -= windowRect.top; ::SetCapture(m_hWnd); } } else if (wMouseMessage == WM_LBUTTONUP) { if (m_bMouseDragable) { // end window drag ::ReleaseCapture(); } } } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnInitMenuPopup(HMENU hMenu, UINT uiPos, BOOL bSysMenu) { if ((hMenu != ::GetSubMenu(m_hPopupMenu, 0)) && (hMenu != m_hSysMenu)) return; // update configuration files submenu UpdateConfigFilesSubmenu(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnDropFiles(HDROP hDrop) { UINT uiFilesCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); tstring strFilenames(_T("")); // concatenate all filenames for (UINT i = 0; i < uiFilesCount; ++i) { TCHAR szFilename[MAX_PATH]; ::ZeroMemory(szFilename, sizeof(szFilename)); ::DragQueryFile(hDrop, i, szFilename, MAX_PATH); tstring strFilename(szFilename); // if there are spaces in the filename, put quotes around it if (strFilename.find(_T(" ")) != tstring::npos) strFilename = tstring(_T("\"")) + strFilename + tstring(_T("\"")); if (i > 0) strFilenames += _T(" "); strFilenames += strFilename; } ::DragFinish(hDrop); // This function takes text, not file names // SendTextToConsole(strFilenames.c_str()); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::OnCommand(WPARAM wParam, LPARAM lParam) { if (HIWORD(wParam) == 0) { // popup menu return HandleMenuCommand(LOWORD(wParam)); } return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::OnSysCommand(WPARAM wParam, LPARAM lParam) { return HandleMenuCommand(wParam); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::OnTrayNotify(WPARAM wParam, LPARAM lParam) { switch (lParam) { case WM_RBUTTONUP: { if (m_bPopupMenuDisabled) return; POINT posCursor; ::GetCursorPos(&posCursor); // show popup menu ::SetForegroundWindow(m_hWnd); ::TrackPopupMenu(::GetSubMenu(m_hPopupMenu, 0), 0, posCursor.x, posCursor.y, 0, m_hWnd, NULL); ::PostMessage(m_hWnd, WM_NULL, 0, 0); return; } case WM_LBUTTONDOWN: m_bHideWindow = false; ShowHideWindow(); ::SetForegroundWindow(m_hWnd); return; case WM_LBUTTONDBLCLK: m_bHideWindow = !m_bHideWindow; ShowHideWindow(); ::SetForegroundWindow(m_hWnd); return; default : return; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #if 0 void Console::OnWallpaperChanged(const TCHAR* pszFilename) { if (m_dwTransparency == TRANSPARENCY_FAKE) { SetWindowTransparency(); CreateBackgroundBitmap(); RepaintWindow(); } } #endif ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::GetOptions() { #if 0 class XmlException { public: XmlException(BOOL bRet) : m_bRet(bRet){}; BOOL m_bRet; }; BOOL bRet = FALSE; IStream* pFileStream = NULL; IXMLDocument* pConfigDoc = NULL; IPersistStreamInit* pPersistStream = NULL; IXMLElement* pRootElement = NULL; IXMLElementCollection* pColl = NULL; IXMLElement* pFontElement = NULL; IXMLElement* pPositionElement = NULL; IXMLElement* pAppearanceElement = NULL; IXMLElement* pScrollbarElement = NULL; IXMLElement* pBackgroundElement = NULL; IXMLElement* pCursorElement = NULL; IXMLElement* pBehaviorElement = NULL; try { ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); USES_CONVERSION; // open file stream if (!SUCCEEDED(CreateFileStream( m_strConfigFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL, &pFileStream))) { throw XmlException(FALSE); } // create XML document instance if (!SUCCEEDED(::CoCreateInstance( CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDocument, (void**)&pConfigDoc))) { throw XmlException(FALSE); } // load the configuration file pConfigDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPersistStream); if (!SUCCEEDED(pPersistStream->Load(pFileStream))) throw XmlException(FALSE); // see if we're dealing with the skin if (!SUCCEEDED(pConfigDoc->get_root(&pRootElement))) throw XmlException(FALSE); CComVariantOut varAttValue; CComBSTROut bstr; CComBSTROut strText; tstring strTempText(_T("")); // root element must be CONSOLE pRootElement->get_tagName(bstr.Out()); bstr.ToUpper(); if (!(bstr == CComBSTR(_T("CONSOLE")))) throw XmlException(FALSE); pRootElement->getAttribute(CComBSTR(_T("title")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { m_strWindowTitle = OLE2T(varAttValue.bstrVal); m_strWindowTitleCurrent = m_strWindowTitle; } pRootElement->getAttribute(CComBSTR(_T("refresh")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_dwMasterRepaintInt = _ttol(OLE2T(varAttValue.bstrVal)); pRootElement->getAttribute(CComBSTR(_T("change_refresh")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_dwChangeRepaintInt = _ttol(OLE2T(varAttValue.bstrVal)); if ((int)m_dwChangeRepaintInt < 5) m_dwChangeRepaintInt = 5; pRootElement->getAttribute(CComBSTR(_T("shell")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_strShell = OLE2T(varAttValue.bstrVal); pRootElement->getAttribute(CComBSTR(_T("editor")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_strConfigEditor = OLE2T(varAttValue.bstrVal); pRootElement->getAttribute(CComBSTR(_T("editor_params")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_strConfigEditorParams = OLE2T(varAttValue.bstrVal); pRootElement->get_children(&pColl); if (!pColl) throw XmlException(TRUE); // get font settings IXMLElementCollection* pFontColl = NULL; if (!SUCCEEDED(pColl->item(CComVariant(_T("font")), CComVariant(0), (IDispatch**)&pFontElement))) throw XmlException(FALSE); if (pFontElement) { if (!SUCCEEDED(pFontElement->get_children(&pFontColl))) throw XmlException(FALSE); if (pFontColl) { IXMLElement* pFontSubelement = NULL; if (!SUCCEEDED(pFontColl->item(CComVariant(_T("size")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { pFontSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_dwFontSize = _ttoi(OLE2T(strText)); } SAFERELEASE(pFontSubelement); if (!SUCCEEDED(pFontColl->item(CComVariant(_T("italic")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { pFontSubelement->get_text(strText.Out()); m_bItalic = !_tcsicmp(OLE2T(strText), _T("true")); } SAFERELEASE(pFontSubelement); if (!SUCCEEDED(pFontColl->item(CComVariant(_T("bold")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { pFontSubelement->get_text(strText.Out()); m_bBold = !_tcsicmp(OLE2T(strText), _T("true")); } SAFERELEASE(pFontSubelement); if (!SUCCEEDED(pFontColl->item(CComVariant(_T("name")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { pFontSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_strFontName = OLE2T(strText); } SAFERELEASE(pFontSubelement); if (!SUCCEEDED(pFontColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; varAttValue.Clear(); pFontSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); varAttValue.Clear(); pFontSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); varAttValue.Clear(); pFontSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); m_bUseFontColor = TRUE; m_crFontColor = RGB(r, g, b); } SAFERELEASE(pFontSubelement); // get font color mapping if (!SUCCEEDED(pFontColl->item(CComVariant(_T("colors")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE); if (pFontSubelement) { IXMLElementCollection* pColorsColl = NULL; if (!SUCCEEDED(pFontSubelement->get_children(&pColorsColl))) throw XmlException(FALSE); if (pColorsColl) { for (int i = 0; i < 16; ++i) { IXMLElement* pColorSubelement = NULL; TCHAR szColorName[32]; _sntprintf(szColorName, sizeof(szColorName)/sizeof(TCHAR), _T("color_%02i"), i); if (!SUCCEEDED(pColorsColl->item(CComVariant(szColorName), CComVariant(0), (IDispatch**)&pColorSubelement))) throw XmlException(FALSE); if (pColorSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; varAttValue.Clear(); pColorSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); varAttValue.Clear(); pColorSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); varAttValue.Clear(); pColorSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); Console::m_arrConsoleColors[i] = RGB(r, g, b); } SAFERELEASE(pColorSubelement); } } SAFERELEASE(pColorsColl); } SAFERELEASE(pFontSubelement); } SAFERELEASE(pFontColl); } // get position settings IXMLElementCollection* pPositionColl = NULL; if (!SUCCEEDED(pColl->item(CComVariant(_T("position")), CComVariant(0), (IDispatch**)&pPositionElement))) throw XmlException(FALSE); if (pPositionElement) { if (!SUCCEEDED(pPositionElement->get_children(&pPositionColl))) throw XmlException(FALSE); if (pPositionColl) { IXMLElement* pPositionSubelement = NULL; if (!m_bReloading) { if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("x")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE); if (pPositionSubelement) { pPositionSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nX = _ttoi(OLE2T(strText)); } SAFERELEASE(pPositionSubelement); if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("y")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE); if (pPositionSubelement) { pPositionSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nY = _ttoi(OLE2T(strText)); } SAFERELEASE(pPositionSubelement); } if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("docked")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE); if (pPositionSubelement) { pPositionSubelement->get_text(strText.Out()); strTempText = OLE2T(strText); if (!_tcsicmp(strTempText.c_str(), _T("top left"))) { m_dwDocked = DOCK_TOP_LEFT; } else if (!_tcsicmp(strTempText.c_str(), _T("top right"))) { m_dwDocked = DOCK_TOP_RIGHT; } else if (!_tcsicmp(strTempText.c_str(), _T("bottom right"))) { m_dwDocked = DOCK_BOTTOM_RIGHT; } else if (!_tcsicmp(strTempText.c_str(), _T("bottom left"))) { m_dwDocked = DOCK_BOTTOM_LEFT; } else { m_dwDocked = DOCK_NONE; } } SAFERELEASE(pPositionSubelement); if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("snap_distance")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE); if (pPositionSubelement) { pPositionSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nSnapDst = _ttoi(OLE2T(strText)); } SAFERELEASE(pPositionSubelement); if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("z_order")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE); if (pPositionSubelement) { pPositionSubelement->get_text(strText.Out()); strTempText = OLE2T(strText); if (!_tcsicmp(strTempText.c_str(), _T("regular"))) { m_dwCurrentZOrder = Z_ORDER_REGULAR; m_dwOriginalZOrder = Z_ORDER_REGULAR; } else if (!_tcsicmp(strTempText.c_str(), _T("on top"))) { m_dwCurrentZOrder = Z_ORDER_ONTOP; m_dwOriginalZOrder = Z_ORDER_ONTOP; } else if (!_tcsicmp(strTempText.c_str(), _T("on bottom"))) { m_dwCurrentZOrder = Z_ORDER_ONBOTTOM; m_dwOriginalZOrder = Z_ORDER_ONBOTTOM; } else { m_dwCurrentZOrder = Z_ORDER_REGULAR; m_dwOriginalZOrder = Z_ORDER_REGULAR; } } SAFERELEASE(pPositionSubelement); } SAFERELEASE(pPositionColl); } // get appearance settings IXMLElementCollection* pAppearanceColl = NULL; if (!SUCCEEDED(pColl->item(CComVariant(_T("appearance")), CComVariant(0), (IDispatch**)&pAppearanceElement))) throw XmlException(FALSE); if (pAppearanceElement) { if (!SUCCEEDED(pAppearanceElement->get_children(&pAppearanceColl))) throw XmlException(FALSE); if (pAppearanceColl) { IXMLElement* pAppearanaceSubelement = NULL; if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("hide_console")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bHideConsole = TRUE; } else { m_bHideConsole = FALSE; } } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("hide_console_timeout")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_dwHideConsoleTimeout = _ttoi(OLE2T(strText)); } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("start_minimized")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bStartMinimized = TRUE; } else { m_bStartMinimized = FALSE; } } SAFERELEASE(pAppearanaceSubelement); IXMLElementCollection* pScrollbarColl = NULL; if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("scrollbar")), CComVariant(0), (IDispatch**)&pScrollbarElement))) throw XmlException(FALSE); if (pScrollbarElement) { if (!SUCCEEDED(pScrollbarElement->get_children(&pScrollbarColl))) throw XmlException(FALSE); if (pScrollbarColl) { IXMLElement* pScrollbarSubelement = NULL; if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE); if (pScrollbarSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; pScrollbarSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); pScrollbarSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); pScrollbarSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); m_crScrollbarColor = RGB(r, g, b); } SAFERELEASE(pScrollbarSubelement); if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("style")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE); if (pScrollbarSubelement) { pScrollbarSubelement->get_text(strText.Out()); strTempText = OLE2T(strText); if (!_tcsicmp(strTempText.c_str(), _T("regular"))) { m_nScrollbarStyle = FSB_REGULAR_MODE; } else if (!_tcsicmp(strTempText.c_str(), _T("flat"))) { m_nScrollbarStyle = FSB_FLAT_MODE; } else if (!_tcsicmp(strTempText.c_str(), _T("encarta"))) { m_nScrollbarStyle = FSB_ENCARTA_MODE; } } SAFERELEASE(pScrollbarSubelement); if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("width")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE); if (pScrollbarSubelement) { pScrollbarSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nScrollbarWidth = _ttoi(OLE2T(strText)); } SAFERELEASE(pScrollbarSubelement); if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("button_height")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE); if (pScrollbarSubelement) { pScrollbarSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nScrollbarButtonHeight = _ttoi(OLE2T(strText)); } SAFERELEASE(pScrollbarSubelement); if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("thumb_height")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE); if (pScrollbarSubelement) { pScrollbarSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nScrollbarThunmbHeight = _ttoi(OLE2T(strText)); } SAFERELEASE(pScrollbarSubelement); } SAFERELEASE(pScrollbarColl); } if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("border")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true")) || !_tcsicmp(OLE2T(strText), _T("regular"))) { m_dwWindowBorder = BORDER_REGULAR; } else if (!_tcsicmp(OLE2T(strText), _T("thin"))) { m_dwWindowBorder = BORDER_THIN; } else { m_dwWindowBorder = BORDER_NONE; } } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("inside_border")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_nInsideBorder = _ttoi(OLE2T(strText)); } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("taskbar_button")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("hide"))) { m_dwTaskbarButton = TASKBAR_BUTTON_HIDE; } else if (!_tcsicmp(OLE2T(strText), _T("tray"))) { m_dwTaskbarButton = TASKBAR_BUTTON_TRAY; } else { m_dwTaskbarButton = TASKBAR_BUTTON_NORMAL; } } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("size")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->getAttribute(CComBSTR(_T("rows")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { if (_tcsicmp(OLE2T(varAttValue.bstrVal), _T("max")) == 0) { m_dwRows = 0; } else { m_dwRows = _ttoi(OLE2T(varAttValue.bstrVal)); } } pAppearanaceSubelement->getAttribute(CComBSTR(_T("columns")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { if (_tcsicmp(OLE2T(varAttValue.bstrVal), _T("max")) == 0) { m_dwColumns = 0; } else { m_dwColumns = _ttoi(OLE2T(varAttValue.bstrVal)); } } pAppearanaceSubelement->getAttribute(CComBSTR(_T("buffer_rows")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { m_dwBufferRows = _ttoi(OLE2T(varAttValue.bstrVal)); m_bUseTextBuffer = TRUE; } else { m_dwBufferRows = m_dwRows; } } SAFERELEASE(pAppearanaceSubelement); if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("transparency")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->getAttribute(CComBSTR(_T("alpha")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byAlpha = (BYTE)_ttoi(OLE2T(varAttValue.bstrVal)); pAppearanaceSubelement->getAttribute(CComBSTR(_T("inactive_alpha")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byInactiveAlpha = (BYTE)_ttoi(OLE2T(varAttValue.bstrVal)); pAppearanaceSubelement->get_text(strText.Out()); strTempText = OLE2T(strText); if (!_tcsicmp(strTempText.c_str(), _T("none"))) { m_dwTransparency = TRANSPARENCY_NONE; } else if (!_tcsicmp(strTempText.c_str(), _T("alpha"))) { m_dwTransparency = TRANSPARENCY_ALPHA; } else if (!_tcsicmp(strTempText.c_str(), _T("color key"))) { m_dwTransparency = TRANSPARENCY_COLORKEY; } else if (!_tcsicmp(strTempText.c_str(), _T("fake"))) { m_dwTransparency = TRANSPARENCY_FAKE; } } SAFERELEASE(pAppearanaceSubelement); // get background settings IXMLElementCollection* pBackgroundColl = NULL; if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("background")), CComVariant(0), (IDispatch**)&pBackgroundElement))) throw XmlException(FALSE); if (pBackgroundElement) { if (!SUCCEEDED(pBackgroundElement->get_children(&pBackgroundColl))) throw XmlException(FALSE); if (pBackgroundColl) { IXMLElement* pBackgroundSubelement = NULL; if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE); if (pBackgroundSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); m_crBackground = RGB(r, g, b); } SAFERELEASE(pBackgroundSubelement); if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("console_color")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE); if (pBackgroundSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); m_crConsoleBackground = RGB(r, g, b); } SAFERELEASE(pBackgroundSubelement); if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("tint")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE); if (pBackgroundSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byTintR = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byTintG = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byTintB = _ttoi(OLE2T(varAttValue.bstrVal)); pBackgroundSubelement->getAttribute(CComBSTR(_T("opacity")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) m_byTintOpacity = _ttoi(OLE2T(varAttValue.bstrVal)); if (m_byTintOpacity > 100) m_byTintOpacity = 50; m_bTintSet = TRUE; } SAFERELEASE(pBackgroundSubelement); if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("image")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE); if (pBackgroundSubelement) { pBackgroundSubelement->getAttribute(CComBSTR(_T("style")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("resize"))) { m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE; } else if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("center"))) { m_dwBackgroundStyle = BACKGROUND_STYLE_CENTER; } else if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("tile"))) { m_dwBackgroundStyle = BACKGROUND_STYLE_TILE; } } pBackgroundSubelement->getAttribute(CComBSTR(_T("relative")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("true"))) { m_bRelativeBackground = TRUE; } else { m_bRelativeBackground = FALSE; } } pBackgroundSubelement->getAttribute(CComBSTR(_T("extend")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) { if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("true"))) { m_bExtendBackground = TRUE; } else { m_bExtendBackground = FALSE; } } pBackgroundSubelement->get_text(strText.Out()); m_strBackgroundFile = OLE2T(strText); m_bBitmapBackground = TRUE; } SAFERELEASE(pBackgroundSubelement); } SAFERELEASE(pBackgroundColl); } IXMLElementCollection* pCursorColl = NULL; if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("cursor")), CComVariant(0), (IDispatch**)&pCursorElement))) throw XmlException(FALSE); if (pCursorElement) { if (!SUCCEEDED(pCursorElement->get_children(&pCursorColl))) throw XmlException(FALSE); if (pCursorColl) { IXMLElement* pCursorSubelement = NULL; if (!SUCCEEDED(pCursorColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pCursorSubelement))) throw XmlException(FALSE); if (pCursorSubelement) { BYTE r = 0; BYTE g = 0; BYTE b = 0; pCursorSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal)); pCursorSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal)); pCursorSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out()); if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal)); m_crCursorColor = RGB(r, g, b); } SAFERELEASE(pCursorSubelement); if (!SUCCEEDED(pCursorColl->item(CComVariant(_T("style")), CComVariant(0), (IDispatch**)&pCursorSubelement))) throw XmlException(FALSE); if (pCursorSubelement) { pCursorSubelement->get_text(strText.Out()); strTempText = OLE2T(strText); if (!_tcsicmp(strTempText.c_str(), _T("none"))) { m_dwCursorStyle = CURSOR_STYLE_NONE; } else if (!_tcsicmp(strTempText.c_str(), _T("XTerm"))) { m_dwCursorStyle = CURSOR_STYLE_XTERM; } else if (!_tcsicmp(strTempText.c_str(), _T("block"))) { m_dwCursorStyle = CURSOR_STYLE_BLOCK; } else if (!_tcsicmp(strTempText.c_str(), _T("noblink block"))) { m_dwCursorStyle = CURSOR_STYLE_NBBLOCK; } else if (!_tcsicmp(strTempText.c_str(), _T("pulse block"))) { m_dwCursorStyle = CURSOR_STYLE_PULSEBLOCK; } else if (!_tcsicmp(strTempText.c_str(), _T("bar"))) { m_dwCursorStyle = CURSOR_STYLE_BAR; } else if (!_tcsicmp(strTempText.c_str(), _T("console"))) { m_dwCursorStyle = CURSOR_STYLE_CONSOLE; } else if (!_tcsicmp(strTempText.c_str(), _T("noblink line"))) { m_dwCursorStyle = CURSOR_STYLE_NBHLINE; } else if (!_tcsicmp(strTempText.c_str(), _T("horizontal line"))) { m_dwCursorStyle = CURSOR_STYLE_HLINE; } else if (!_tcsicmp(strTempText.c_str(), _T("vertical line"))) { m_dwCursorStyle = CURSOR_STYLE_VLINE; } else if (!_tcsicmp(strTempText.c_str(), _T("rect"))) { m_dwCursorStyle = CURSOR_STYLE_RECT; } else if (!_tcsicmp(strTempText.c_str(), _T("noblink rect"))) { m_dwCursorStyle = CURSOR_STYLE_NBRECT; } else if (!_tcsicmp(strTempText.c_str(), _T("pulse rect"))) { m_dwCursorStyle = CURSOR_STYLE_PULSERECT; } else if (!_tcsicmp(strTempText.c_str(), _T("fading block"))) { m_dwCursorStyle = CURSOR_STYLE_FADEBLOCK; } } SAFERELEASE(pCursorSubelement); } SAFERELEASE(pCursorColl); } if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("icon")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE); if (pAppearanaceSubelement) { pAppearanaceSubelement->get_text(strText.Out()); if (strText.Length() > 0) m_strIconFilename = OLE2T(strText); } SAFERELEASE(pAppearanaceSubelement); } SAFERELEASE(pAppearanceColl); } // get behaviour settings IXMLElementCollection* pBehaviorColl = NULL; if (!SUCCEEDED(pColl->item(CComVariant(_T("behaviour")), CComVariant(0), (IDispatch**)&pBehaviorElement))) { if (!SUCCEEDED(pColl->item(CComVariant(_T("behavior")), CComVariant(0), (IDispatch**)&pBehaviorElement))) throw XmlException(FALSE); } if (pBehaviorElement) { if (!SUCCEEDED(pBehaviorElement->get_children(&pBehaviorColl))) throw XmlException(FALSE); if (pBehaviorColl) { IXMLElement* pBehaviourSubelement = NULL; if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("mouse_drag")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE); if (pBehaviourSubelement) { pBehaviourSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bMouseDragable = TRUE; } else { m_bMouseDragable = FALSE; } } SAFERELEASE(pBehaviourSubelement); if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("copy_on_select")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE); if (pBehaviourSubelement) { pBehaviourSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bCopyOnSelect = TRUE; } else { m_bCopyOnSelect = FALSE; } } SAFERELEASE(pBehaviourSubelement); if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("inverse_shift")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE); if (pBehaviourSubelement) { pBehaviourSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bInverseShift = TRUE; } else { m_bInverseShift = FALSE; } } SAFERELEASE(pBehaviourSubelement); if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("reload_new_config")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE); if (pBehaviourSubelement) { pBehaviourSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("yes"))) { m_dwReloadNewConfig = RELOAD_NEW_CONFIG_YES; } else if (!_tcsicmp(OLE2T(strText), _T("no"))) { m_dwReloadNewConfig = RELOAD_NEW_CONFIG_NO; } else { m_dwReloadNewConfig = RELOAD_NEW_CONFIG_PROMPT; } } SAFERELEASE(pBehaviourSubelement); if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("disable_menu")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE); if (pBehaviourSubelement) { pBehaviourSubelement->get_text(strText.Out()); if (!_tcsicmp(OLE2T(strText), _T("true"))) { m_bPopupMenuDisabled = TRUE; } else { m_bPopupMenuDisabled = FALSE; } } SAFERELEASE(pBehaviourSubelement); } SAFERELEASE(pBehaviorColl); } bRet = TRUE; } catch (const XmlException& e) { bRet = e.m_bRet; } SAFERELEASE(pBehaviorElement); SAFERELEASE(pCursorElement); SAFERELEASE(pBackgroundElement); SAFERELEASE(pScrollbarElement); SAFERELEASE(pAppearanceElement); SAFERELEASE(pPositionElement); SAFERELEASE(pFontElement); SAFERELEASE(pColl); SAFERELEASE(pRootElement); SAFERELEASE(pPersistStream); SAFERELEASE(pConfigDoc); SAFERELEASE(pFileStream); ::CoUninitialize(); return bRet; #endif return 1; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::RegisterWindowClasses() { WNDCLASSEX wcx; // register the Console window class ::ZeroMemory(&wcx, sizeof(WNDCLASSEX)); wcx.cbSize = sizeof(wcx); wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; wcx.lpfnWndProc = Console::WindowProc; wcx.cbClsExtra = 0; wcx.cbWndExtra = sizeof(void*); wcx.hInstance = ghInstance; wcx.hIcon = ::LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_ICON2)); wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcx.hbrBackground = ::CreateSolidBrush(RGB(0, 0, 0)); wcx.lpszMenuName = NULL; wcx.lpszClassName = Console::m_szConsoleClass; wcx.hIconSm = NULL; if ((::RegisterClassEx(&wcx) == 0) && (::GetLastError() != ERROR_CLASS_ALREADY_EXISTS)) return FALSE; // register the hidden parent window class ::ZeroMemory(&wcx, sizeof(WNDCLASSEX)); wcx.cbSize = sizeof(wcx); wcx.style = 0; wcx.lpfnWndProc = ::DefWindowProc; wcx.cbClsExtra = 0; wcx.cbWndExtra = 0; wcx.hInstance = ghInstance; wcx.hIcon = NULL; wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcx.hbrBackground = NULL; wcx.lpszMenuName = NULL; wcx.lpszClassName = Console::m_szHiddenParentClass; wcx.hIconSm = NULL; if ((::RegisterClassEx(&wcx) == 0) && (::GetLastError() != ERROR_CLASS_ALREADY_EXISTS)) return FALSE; return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::SetupMenus() { MENUITEMINFO mii; // setup popup menu if ((m_hPopupMenu = ::LoadMenu(ghInstance, MAKEINTRESOURCE(IDR_POPUP_MENU))) == NULL) return FALSE; if ((m_hConfigFilesMenu = ::CreateMenu()) == NULL) return FALSE; // add stuff to the system menu TCHAR* arrMenuItems[] = {_T("&Copy"), _T("&Paste")}; DWORD arrMenuTypes[] = {MFT_STRING, MFT_STRING}; DWORD arrMenuIDs[] = { ID_COPY, ID_PASTE}; m_hSysMenu = ::GetSystemMenu(m_hWnd, FALSE); for (int i = 0; i < sizeof(arrMenuIDs)/sizeof(arrMenuIDs[0]); ++i) { ::ZeroMemory(&mii, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE | MIIM_ID; mii.fType = arrMenuTypes[i]; if (mii.fType == MFT_STRING) { mii.wID = arrMenuIDs[i]; mii.dwTypeData = arrMenuItems[i]; mii.cch = _tcslen(arrMenuItems[i]); } else { mii.wID = 0; } ::InsertMenuItem(m_hSysMenu, SC_CLOSE, FALSE, &mii); } // set config files menu as a submenu of "Select configuration file" item // in the popup and system menus ::ZeroMemory(&mii, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_SUBMENU; mii.hSubMenu = m_hConfigFilesMenu; // ::SetMenuItemInfo(m_hPopupMenu, ID_SEL_CONFIG_FILE, FALSE, &mii); // ::SetMenuItemInfo(m_hSysMenu, ID_SEL_CONFIG_FILE, FALSE, &mii); // load the initial list (so the list can be used by external programs) UpdateConfigFilesSubmenu(); return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::CreateConsoleWindow() { // create the window DWORD dwWindowStyle = WS_VSCROLL; if (m_dwTaskbarButton == TASKBAR_BUTTON_NORMAL) dwWindowStyle |= WS_MINIMIZEBOX; switch (m_dwWindowBorder) { case BORDER_NONE : dwWindowStyle |= WS_POPUPWINDOW & ~WS_BORDER; break; case BORDER_REGULAR : dwWindowStyle |= WS_CAPTION|WS_SYSMENU; break; case BORDER_THIN : dwWindowStyle |= WS_POPUPWINDOW; break; default: dwWindowStyle |= WS_POPUPWINDOW & ~WS_BORDER; } // If the taskbar style is set to hide or tray, we create an invisible window // to parent the main window to. This hides the taskbar button while allowing // us to use the normal title bar. if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) { if ((m_hwndInvisParent = ::CreateWindowEx( WS_EX_TOOLWINDOW, Console::m_szHiddenParentClass, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, ghInstance, NULL)) == NULL) { return FALSE; } // don't let the user minimize it if there's no way to restore it if (m_dwTaskbarButton == TASKBAR_BUTTON_HIDE) dwWindowStyle &= ~WS_MINIMIZEBOX; } if ((m_hWnd = ::CreateWindowEx( 0, //m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL ? WS_EX_TOOLWINDOW : 0, Console::m_szConsoleClass, m_strWindowTitle.c_str(), dwWindowStyle, ((m_nX == -1) || (m_nY == -1)) ? CW_USEDEFAULT : 0, 0, 0, 0, m_hwndInvisParent, NULL, ghInstance, NULL)) == NULL) { return FALSE; } ::SetWindowLongPtr( m_hWnd, GWLP_USERDATA, (LONG_PTR)this); if ((m_nX == -1) || (m_nY == -1)) { RECT rectWindow; ::GetWindowRect(m_hWnd, &rectWindow); m_nX = (int)rectWindow.left; m_nY = (int)rectWindow.top; } return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CreateNewFont() { // create a new font if (m_hFontOld) ::SelectObject(m_hdcConsole, m_hFontOld); if (m_hFont) ::DeleteObject(m_hFont); m_hFont = ::CreateFont( -MulDiv(m_dwFontSize, ::GetDeviceCaps(m_hdcConsole, LOGPIXELSY), 72), 0, 0, 0, m_bBold ? FW_BOLD : 0, m_bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, m_strFontName.c_str()); m_hFontOld = (HFONT)::SelectObject(m_hdcConsole, m_hFont); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CreateNewBrush() { // create a new background brush if (m_hBkBrush) ::DeleteObject(m_hBkBrush); m_hBkBrush = ::CreateSolidBrush(m_crBackground); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CreateCursor() { switch (m_dwCursorStyle) { case CURSOR_STYLE_XTERM : m_pCursor = (Cursor*)new XTermCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_BLOCK : m_pCursor = (Cursor*)new BlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_NBBLOCK : m_pCursor = (Cursor*)new NBBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_PULSEBLOCK : m_pCursor = (Cursor*)new PulseBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_BAR : m_pCursor = (Cursor*)new BarCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_CONSOLE : m_pCursor = (Cursor*)new ConsoleCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_NBHLINE : m_pCursor = (Cursor*)new NBHLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_HLINE : m_pCursor = (Cursor*)new HLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_VLINE : m_pCursor = (Cursor*)new VLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_RECT : m_pCursor = (Cursor*)new RectCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_NBRECT : m_pCursor = (Cursor*)new NBRectCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_PULSERECT : m_pCursor = (Cursor*)new PulseRectCursor(m_hWnd, m_hdcConsole, m_crCursorColor); break; case CURSOR_STYLE_FADEBLOCK : m_pCursor = (Cursor*)new FadeBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor, m_crBackground); break; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CreateOffscreenBuffers() { HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0); // create new window bitmap if (m_hbmpConsoleOld) ::SelectObject(m_hdcConsole, m_hbmpConsoleOld); if (m_hbmpConsole) ::DeleteObject(m_hbmpConsole); m_hbmpConsole = ::CreateCompatibleBitmap(hdcDesktop, m_nClientWidth, m_nClientHeight); m_hbmpConsoleOld = (HBITMAP)::SelectObject(m_hdcConsole, m_hbmpConsole); if (m_hbmpWindowOld) ::SelectObject(m_hdcWindow, m_hbmpWindowOld); if (m_hbmpWindow) ::DeleteObject(m_hbmpWindow); m_hbmpWindow = ::CreateCompatibleBitmap(hdcDesktop, m_nClientWidth, m_nClientHeight); m_hbmpWindowOld = (HBITMAP)::SelectObject(m_hdcWindow, m_hbmpWindow); // create selection bitmap if (m_hbmpSelectionOld) ::SelectObject(m_hdcSelection, m_hbmpSelectionOld); if (m_hbmpSelection) ::DeleteObject(m_hbmpSelection); m_hbmpSelection = ::CreateCompatibleBitmap(m_hdcWindow, m_nClientWidth, m_nClientHeight); m_hbmpSelectionOld = (HBITMAP)::SelectObject(m_hdcSelection, m_hbmpSelection); RECT rect; rect.left = 0; rect.top = 0; rect.right = m_nClientWidth; rect.bottom = m_nClientHeight; ::FillRect(m_hdcSelection, &rect, m_hbrushSelection); ::ReleaseDC(m_hWnd, hdcDesktop); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #if 0 void Console::CreateBackgroundBitmap() { USES_CONVERSION; if (m_hbmpBackgroundOld) ::SelectObject(m_hdcBackground, m_hbmpBackgroundOld); if (m_hbmpBackground) ::DeleteObject(m_hbmpBackground); if (m_hdcBackground) ::DeleteDC(m_hdcBackground); if (!m_bBitmapBackground) return; // determine the total size of the background bitmap DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN); DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN); DWORD dwBackgroundWidth = 0; DWORD dwBackgroundHeight = 0; if (m_bRelativeBackground) { if (g_bWin2000) { // Win2K and later can handle multiple monitors dwBackgroundWidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); dwBackgroundHeight = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); // get offsets for virtual display m_nBackgroundOffsetX = ::GetSystemMetrics(SM_XVIRTUALSCREEN); m_nBackgroundOffsetY = ::GetSystemMetrics(SM_YVIRTUALSCREEN); } else { // WinNT compatibility (hope it works, I didn't test it) dwBackgroundWidth = dwPrimaryDisplayWidth; dwBackgroundHeight = dwBackgroundHeight; } } else { dwBackgroundWidth = m_nClientWidth; dwBackgroundHeight = m_nClientHeight; } // now, load the image... fipImage image; IMAGE_DATA imageData; if (!image.load(T2A(m_strBackgroundFile.c_str()))) { m_bBitmapBackground = FALSE; return; } imageData.hdcImage = NULL; imageData.dwImageWidth = image.getWidth(); imageData.dwImageHeight = image.getHeight(); image.convertTo24Bits(); // ... if needed, tint the background image if (m_bTintSet) { BYTE* pPixels = image.accessPixels(); BYTE* pPixelsEnd = pPixels + 3*image.getWidth()*image.getHeight(); BYTE* pPixelSubel = pPixels; while (pPixelSubel < pPixelsEnd) { *pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintB*m_byTintOpacity)/100); ++pPixelSubel; *pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintG*m_byTintOpacity)/100); ++pPixelSubel; *pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintR*m_byTintOpacity)/100); ++pPixelSubel; } } // create the basic image HBITMAP hbmpImage = NULL; HBITMAP hbmpImageOld = NULL; if (m_dwBackgroundStyle == BACKGROUND_STYLE_RESIZE) { if (m_bRelativeBackground) { if (m_bExtendBackground) { imageData.dwImageWidth = dwBackgroundWidth; imageData.dwImageHeight = dwBackgroundHeight; } else { imageData.dwImageWidth = dwPrimaryDisplayWidth; imageData.dwImageHeight = dwPrimaryDisplayHeight; } } else { imageData.dwImageWidth = (DWORD)m_nClientWidth; imageData.dwImageHeight = (DWORD)m_nClientHeight; } if ((image.getWidth() != imageData.dwImageWidth) || (image.getHeight() != imageData.dwImageHeight)) { image.rescale(imageData.dwImageWidth, imageData.dwImageHeight, FILTER_LANCZOS3); } } // now, create a DC compatible with the screen and create the basic bitmap HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0); imageData.hdcImage = ::CreateCompatibleDC(hdcDesktop); hbmpImage = ::CreateDIBitmap( hdcDesktop, image.getInfoHeader(), CBM_INIT, image.accessPixels(), image.getInfo(), DIB_RGB_COLORS); hbmpImageOld= (HBITMAP)::SelectObject(imageData.hdcImage, hbmpImage); ::ReleaseDC(m_hWnd, hdcDesktop); // create the background image m_hdcBackground = ::CreateCompatibleDC(imageData.hdcImage); m_hbmpBackground = ::CreateCompatibleBitmap(imageData.hdcImage, dwBackgroundWidth, dwBackgroundHeight); m_hbmpBackgroundOld = (HBITMAP)::SelectObject(m_hdcBackground, m_hbmpBackground); RECT rectBackground; rectBackground.left = 0; rectBackground.top = 0; rectBackground.right = dwBackgroundWidth; rectBackground.bottom = dwBackgroundHeight; // fill the background with the proper background color in case the // bitmap doesn't cover the entire background, COLORREF crBackground; if (m_dwTransparency == TRANSPARENCY_FAKE) { // get desktop background color HKEY hkeyColors; if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Colors"), 0, KEY_READ, &hkeyColors) == ERROR_SUCCESS) { TCHAR szData[MAX_PATH]; DWORD dwDataSize = MAX_PATH; BYTE r = 0; BYTE g = 0; BYTE b = 0; ::ZeroMemory(szData, sizeof(szData)); ::RegQueryValueEx(hkeyColors, _T("Background"), NULL, NULL, (BYTE*)szData, &dwDataSize); _stscanf(szData, _T("%i %i %i"), &r, &g, &b); crBackground = RGB(r, g, b); ::RegCloseKey(hkeyColors); } } else { ::CopyMemory(&crBackground, &m_crBackground, sizeof(COLORREF)); } HBRUSH hBkBrush = ::CreateSolidBrush(crBackground); ::FillRect(m_hdcBackground, &rectBackground, hBkBrush); ::DeleteObject(hBkBrush); if (m_dwBackgroundStyle == BACKGROUND_STYLE_TILE) { // we're tiling the image, starting at coordinates (0, 0) of the virtual screen DWORD dwX = 0; DWORD dwY = 0; DWORD dwImageOffsetX = 0; DWORD dwImageOffsetY = imageData.dwImageHeight + (m_nBackgroundOffsetY - (int)imageData.dwImageHeight*(m_nBackgroundOffsetY/(int)imageData.dwImageHeight)); while (dwY < dwBackgroundHeight) { dwX = 0; dwImageOffsetX = imageData.dwImageWidth + (m_nBackgroundOffsetX - (int)imageData.dwImageWidth*(m_nBackgroundOffsetX/(int)imageData.dwImageWidth)); while (dwX < dwBackgroundWidth) { ::BitBlt( m_hdcBackground, dwX, dwY, imageData.dwImageWidth, imageData.dwImageHeight, imageData.hdcImage, dwImageOffsetX, dwImageOffsetY, SRCCOPY); dwX += imageData.dwImageWidth - dwImageOffsetX; dwImageOffsetX = 0; } dwY += imageData.dwImageHeight - dwImageOffsetY; dwImageOffsetY = 0; } } else if (m_bExtendBackground || !m_bRelativeBackground) { switch (m_dwBackgroundStyle) { case BACKGROUND_STYLE_RESIZE : ::BitBlt( m_hdcBackground, 0, 0, dwBackgroundWidth, dwBackgroundHeight, imageData.hdcImage, 0, 0, SRCCOPY); break; case BACKGROUND_STYLE_CENTER : ::BitBlt( m_hdcBackground, (dwBackgroundWidth <= imageData.dwImageWidth) ? 0 : (dwBackgroundWidth - imageData.dwImageWidth)/2, (dwBackgroundHeight <= imageData.dwImageHeight) ? 0 : (dwBackgroundHeight - imageData.dwImageHeight)/2, imageData.dwImageWidth, imageData.dwImageHeight, imageData.hdcImage, (dwBackgroundWidth < imageData.dwImageWidth) ? (imageData.dwImageWidth - dwBackgroundWidth)/2 : 0, (dwBackgroundHeight < imageData.dwImageHeight) ? (imageData.dwImageHeight - dwBackgroundHeight)/2 : 0, SRCCOPY); break; } } else { ::EnumDisplayMonitors(NULL, NULL, Console::BackgroundEnumProc, (DWORD)&imageData); } ::SelectObject(imageData.hdcImage, hbmpImageOld); ::DeleteObject(hbmpImage); ::DeleteDC(imageData.hdcImage); } #endif ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #if 0 BOOL CALLBACK Console::BackgroundEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { IMAGE_DATA* pImageData = (IMAGE_DATA*)dwData; DWORD dwDisplayWidth = lprcMonitor->right - lprcMonitor->left; DWORD dwDisplayHeight = lprcMonitor->bottom - lprcMonitor->top; DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN); DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN); // center the image according to current display's size and position switch (g_pConsole->m_dwBackgroundStyle) { case BACKGROUND_STYLE_RESIZE : ::BitBlt( g_pConsole->m_hdcBackground, (dwDisplayWidth <= dwPrimaryDisplayWidth) ? lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX : lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX + (dwDisplayWidth - dwPrimaryDisplayWidth)/2, (dwDisplayHeight <= dwPrimaryDisplayHeight) ? lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY : lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY + (dwDisplayHeight - dwPrimaryDisplayHeight)/2, dwDisplayWidth, dwDisplayHeight, pImageData->hdcImage, (dwDisplayWidth < dwPrimaryDisplayWidth) ? (dwPrimaryDisplayWidth - dwDisplayWidth)/2 : 0, (dwDisplayHeight < dwPrimaryDisplayHeight) ? (dwPrimaryDisplayHeight - dwDisplayHeight)/2 : 0, SRCCOPY); break; case BACKGROUND_STYLE_CENTER : ::BitBlt( g_pConsole->m_hdcBackground, (dwDisplayWidth <= pImageData->dwImageWidth) ? lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX : lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX + (dwDisplayWidth - pImageData->dwImageWidth)/2, (dwDisplayHeight <= pImageData->dwImageHeight) ? lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY : lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY + (dwDisplayHeight - pImageData->dwImageHeight)/2, dwDisplayWidth, dwDisplayHeight, pImageData->hdcImage, (dwDisplayWidth < pImageData->dwImageWidth) ? (pImageData->dwImageWidth - dwDisplayWidth)/2 : 0, (dwDisplayHeight < pImageData->dwImageHeight) ? (pImageData->dwImageHeight - dwDisplayHeight)/2 : 0, SRCCOPY); break; } return TRUE; } #endif ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::GetTextSize() { TEXTMETRIC textMetric; ::GetTextMetrics(m_hdcConsole, &textMetric); m_nCharHeight = textMetric.tmHeight; if (!(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH)) { // fixed pitch font (TMPF_FIXED_PITCH is cleared!!!) m_nCharWidth = textMetric.tmAveCharWidth; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::GetBordersDimensions() { WINDOWINFO wndInfo; TITLEBARINFO titlebarInfo; ::ZeroMemory(&wndInfo, sizeof(WINDOWINFO)); ::ZeroMemory(&titlebarInfo, sizeof(TITLEBARINFO)); wndInfo.cbSize = sizeof(WINDOWINFO); titlebarInfo.cbSize = sizeof(TITLEBARINFO); ::GetWindowInfo(m_hWnd, &wndInfo); ::GetTitleBarInfo(m_hWnd, &titlebarInfo); m_nXBorderSize = wndInfo.cxWindowBorders; m_nYBorderSize = wndInfo.cyWindowBorders; m_nCaptionSize = (titlebarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE) ? 0 : titlebarInfo.rcTitleBar.bottom - titlebarInfo.rcTitleBar.top; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CalcWindowSize() { m_nClientHeight = m_dwRows * m_nCharHeight + 2*m_nInsideBorder; if (m_nCharWidth > 0) { // fixed pitch font m_nClientWidth = m_dwColumns * m_nCharWidth + 2*m_nInsideBorder; } else { // variable pitch font int nCharWidth; ::GetCharWidth32(m_hdcConsole, _TCHAR('m'), _TCHAR('m'), &nCharWidth); m_nClientWidth = m_dwColumns * nCharWidth; } switch (m_dwWindowBorder) { case BORDER_NONE : m_nWindowHeight = m_nClientHeight; m_nWindowWidth = m_nClientWidth; break; case BORDER_REGULAR : { m_nWindowHeight = m_nClientHeight + m_nCaptionSize + 2*m_nYBorderSize; m_nWindowWidth = m_nClientWidth + 2 * m_nXBorderSize; break; } case BORDER_THIN : m_nWindowHeight = m_nClientHeight + 2*m_nYBorderSize; m_nWindowWidth = m_nClientWidth + 2*m_nXBorderSize; } if (m_bShowScrollbar) m_nWindowWidth += m_nScrollbarWidth; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #if 0 void Console::SetWindowTransparency() { // set alpha transparency (Win2000 and later only!) if (g_bWin2000 && ((m_dwTransparency == TRANSPARENCY_ALPHA) || (m_dwTransparency == TRANSPARENCY_COLORKEY))) { ::SetWindowLong(m_hWnd, GWL_EXSTYLE, ::GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byAlpha, m_dwTransparency == TRANSPARENCY_ALPHA ? LWA_ALPHA : LWA_COLORKEY); } else if (m_dwTransparency == TRANSPARENCY_FAKE) { // get wallpaper settings HKEY hkeyDesktop; if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"), 0, KEY_READ, &hkeyDesktop) == ERROR_SUCCESS) { TCHAR szData[MAX_PATH]; DWORD dwDataSize = MAX_PATH; DWORD dwWallpaperStyle; DWORD dwTileWallpaper; ::ZeroMemory(szData, sizeof(szData)); ::RegQueryValueEx(hkeyDesktop, _T("Wallpaper"), NULL, NULL, (BYTE*)szData, &dwDataSize); if (_tcslen(szData) > 0) { m_bBitmapBackground = TRUE; m_strBackgroundFile = szData; m_bRelativeBackground = TRUE; m_bExtendBackground = FALSE; // get wallpaper style and tile flag dwDataSize = MAX_PATH; ::ZeroMemory(szData, sizeof(szData)); ::RegQueryValueEx(hkeyDesktop, _T("WallpaperStyle"), NULL, NULL, (BYTE*)szData, &dwDataSize); dwWallpaperStyle = _ttoi(szData); dwDataSize = MAX_PATH; ::ZeroMemory(szData, sizeof(szData)); ::RegQueryValueEx(hkeyDesktop, _T("TileWallpaper"), NULL, NULL, (BYTE*)szData, &dwDataSize); dwTileWallpaper = _ttoi(szData); if (dwTileWallpaper == 1) { m_dwBackgroundStyle = BACKGROUND_STYLE_TILE; } else { if (dwWallpaperStyle == 0) { m_dwBackgroundStyle = BACKGROUND_STYLE_CENTER; } else { m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE; } } } ::RegCloseKey(hkeyDesktop); } } } #endif ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::SetScrollbarStuff() { if (m_bUseTextBuffer) { m_bShowScrollbar = m_dwBufferRows > m_dwRows; } else { m_bShowScrollbar = FALSE; } // we don't call InitializeFlatSB due to some problems on Win2k, Windowblinds and new-style scrollbars if (m_nScrollbarStyle != FSB_REGULAR_MODE) ::InitializeFlatSB(m_hWnd); ::FlatSB_ShowScrollBar(m_hWnd, SB_VERT, m_bShowScrollbar); ::FlatSB_SetScrollRange(m_hWnd, SB_VERT, 0, m_dwBufferRows-m_dwRows, FALSE); // set scrollbar properties ::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_VSTYLE, m_nScrollbarStyle, FALSE); ::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_VBKGCOLOR, m_crScrollbarColor, FALSE); ::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CXVSCROLL , m_nScrollbarWidth, FALSE); ::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CYVSCROLL, m_nScrollbarButtonHeight, FALSE); ::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CYVTHUMB, m_nScrollbarThunmbHeight, TRUE); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::SetDefaultConsoleColors() { m_arrConsoleColors[0] = 0x000000; m_arrConsoleColors[1] = 0x800000; m_arrConsoleColors[2] = 0x008000; m_arrConsoleColors[3] = 0x808000; m_arrConsoleColors[4] = 0x000080; m_arrConsoleColors[5] = 0x800080; m_arrConsoleColors[6] = 0x008080; m_arrConsoleColors[7] = 0xC0C0C0; m_arrConsoleColors[8] = 0x808080; m_arrConsoleColors[9] = 0xFF0000; m_arrConsoleColors[10] = 0x00FF00; m_arrConsoleColors[11] = 0xFFFF00; m_arrConsoleColors[12] = 0x0000FF; m_arrConsoleColors[13] = 0xFF00FF; m_arrConsoleColors[14] = 0x00FFFF; m_arrConsoleColors[15] = 0xFFFFFF; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::SetWindowSizeAndPosition() { // set window position #if 0 DWORD dwScreenWidth = ::GetSystemMetrics(g_bWin2000 ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); DWORD dwScreenHeight = ::GetSystemMetrics(g_bWin2000 ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); DWORD dwTop = ::GetSystemMetrics(g_bWin2000 ? SM_YVIRTUALSCREEN : 0); DWORD dwLeft = ::GetSystemMetrics(g_bWin2000 ? SM_XVIRTUALSCREEN : 0); #else DWORD dwScreenWidth = ::GetSystemMetrics(SM_CXSCREEN); DWORD dwScreenHeight = ::GetSystemMetrics(SM_CYSCREEN); DWORD dwTop = ::GetSystemMetrics(0); DWORD dwLeft = ::GetSystemMetrics(0); #endif switch (m_dwDocked) { case DOCK_TOP_LEFT: // top left m_nX = dwLeft; m_nY = dwTop; break; case DOCK_TOP_RIGHT: // top right m_nX = dwScreenWidth - m_nWindowWidth; m_nY = dwTop; break; case DOCK_BOTTOM_RIGHT: // bottom right m_nX = dwScreenWidth - m_nWindowWidth; m_nY = dwScreenHeight - m_nWindowHeight; break; case DOCK_BOTTOM_LEFT: // bottom left m_nX = dwLeft; m_nY = dwScreenHeight - m_nWindowHeight; break; } HWND hwndZ = 0; switch (m_dwCurrentZOrder) { case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break; case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break; case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break; default : return; } ::SetWindowPos( m_hWnd, hwndZ, m_nX, m_nY, m_nWindowWidth, m_nWindowHeight, 0); UpdateOnTopMenuItem(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::SetWindowIcons() { HICON hOldIcon = NULL; if (m_strIconFilename.length() > 0) { // custom icon, try loading it... if ((m_hSmallIcon = (HICON)::LoadImage(NULL, m_strIconFilename.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE)) != NULL) { // icon file exists, load and set the big icon as well m_hBigIcon = (HICON)::LoadImage(NULL, m_strIconFilename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); hOldIcon = (HICON)::SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)m_hBigIcon); if (hOldIcon) ::DestroyIcon(hOldIcon); } else { m_hSmallIcon = (HICON)::LoadImage(ghInstance, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 16, 16, 0); } } else { m_hSmallIcon = (HICON)::LoadImage(ghInstance, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 16, 16, 0); } hOldIcon = (HICON)::SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hSmallIcon); if (hOldIcon) ::DestroyIcon(hOldIcon); SetTrayIcon(m_dwTaskbarButton == TASKBAR_BUTTON_TRAY ? NIM_ADD : NIM_DELETE); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::SetTrayIcon(DWORD dwMessage) { NOTIFYICONDATA tnd; tstring strToolTip(m_strWindowTitle); tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = m_hWnd; tnd.uID = TRAY_ICON_ID; tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; tnd.uCallbackMessage = WM_TRAY_NOTIFY; tnd.hIcon = m_hSmallIcon; if (strToolTip.length() > 63) { strToolTip.resize(59); strToolTip += _T(" ..."); // DWORD dw = strToolTip.length(); } _tcscpy(tnd.szTip, strToolTip.c_str()); return ::Shell_NotifyIcon(dwMessage, &tnd); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::DestroyCursor() { if (m_pCursor) { delete m_pCursor; m_pCursor = NULL; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::EditConfigFile() { // prepare editor parameters tstring strParams(m_strConfigEditorParams); if (strParams.length() == 0) { // no params, just use the config file strParams = m_strConfigFile; } else { tstring::size_type nPos = strParams.find(_T("%f")); if (nPos == tstring::npos) { // no '%f' in editor params, concatenate config file name strParams += _T(" "); strParams += m_strConfigFile; } else { // replace '%f' with config file name strParams = strParams.replace(nPos, 2, m_strConfigFile); } } // start editor ::ShellExecute(NULL, NULL, m_strConfigEditor.c_str(), strParams.c_str(), NULL, SW_SHOWNORMAL); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ReloadSettings() { m_bInitializing = TRUE; m_bReloading = TRUE; // suspend console monitor thread ::SuspendThread(m_hMonitorThread); ::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE); if (m_dwMasterRepaintInt) ::KillTimer(m_hWnd, TIMER_REPAINT_MASTER); // hide Windows console ::ShowWindow(m_hWndConsole, SW_HIDE); // destroy icons SetTrayIcon(NIM_DELETE); if (m_hSmallIcon) ::DestroyIcon(m_hSmallIcon); if (m_hBigIcon) ::DestroyIcon(m_hBigIcon); // destroy cursor DestroyCursor(); // destory menus ::DestroyMenu(m_hConfigFilesMenu); ::DestroyMenu(m_hPopupMenu); // uninitialize flat scrollbars if (m_nScrollbarStyle != FSB_REGULAR_MODE) ::UninitializeFlatSB(m_hWnd); // destory window ::DestroyWindow(m_hWnd); if (m_hwndInvisParent) ::DestroyWindow(m_hwndInvisParent); // set default values m_strShell = _T(""); m_strConfigEditor = _T("notepad.exe"); m_strConfigEditorParams = _T(""); m_dwReloadNewConfig = m_dwReloadNewConfigDefault; m_hwndInvisParent = NULL; m_dwMasterRepaintInt = 500; m_dwChangeRepaintInt = 50; m_strIconFilename = _T(""); m_hSmallIcon = NULL; m_hBigIcon = NULL; m_hPopupMenu = NULL; m_hConfigFilesMenu = NULL; m_bPopupMenuDisabled = FALSE; m_strWindowTitle = m_strWindowTitleDefault; m_strWindowTitleCurrent = m_strWindowTitleDefault; m_strFontName = _T("Courier New"); m_dwFontSize = 10; m_bBold = FALSE; m_bItalic = FALSE; m_bUseFontColor = FALSE; m_crFontColor = RGB(0, 0, 0); m_nWindowWidth = 0; m_nWindowHeight = 0; m_nXBorderSize = 5; m_nYBorderSize = 5; m_nCaptionSize = 0; m_nClientWidth = 0; m_nClientHeight = 0; m_nCharHeight = 0; m_nCharWidth = 0; m_dwWindowBorder = BORDER_REGULAR; m_bShowScrollbar = TRUE; m_nScrollbarStyle = FSB_REGULAR_MODE; m_crScrollbarColor = ::GetSysColor(COLOR_3DHILIGHT); m_nScrollbarWidth = ::GetSystemMetrics(SM_CXVSCROLL); m_nScrollbarButtonHeight= ::GetSystemMetrics(SM_CYVSCROLL); m_nScrollbarThunmbHeight= ::GetSystemMetrics(SM_CYVTHUMB); m_dwTaskbarButton = TASKBAR_BUTTON_NORMAL; m_bMouseDragable = TRUE; m_nSnapDst = 10; m_dwDocked = DOCK_NONE; m_dwOriginalZOrder = Z_ORDER_REGULAR; m_dwCurrentZOrder = Z_ORDER_REGULAR; m_dwTransparency = TRANSPARENCY_NONE; m_byAlpha = 150; m_byInactiveAlpha = 150; m_crBackground = RGB(0, 0, 0); m_crConsoleBackground = RGB(0, 0, 0); m_bTintSet = FALSE; m_byTintOpacity = 50; m_byTintR = 0; m_byTintG = 0; m_byTintB = 0; m_bBitmapBackground = FALSE; m_strBackgroundFile = _T(""); m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE; m_bRelativeBackground = FALSE; m_bExtendBackground = FALSE; m_bHideWindow = FALSE; m_bHideConsole = TRUE; m_dwCursorStyle = CURSOR_STYLE_CONSOLE; m_bStartMinimized = FALSE; m_crCursorColor = RGB(255, 255, 255); m_bCursorVisible = TRUE; m_dwRows = 50; m_dwColumns = 80; m_dwBufferRows = 500; m_bUseTextBuffer = TRUE; m_bCopyOnSelect = FALSE; m_nTextColor = 15; m_nTextBgColor = 0; SetDefaultConsoleColors(); GetOptions(); CreateConsoleWindow(); SetupMenus(); CreateNewFont(); CreateNewBrush(); // SetWindowTransparency(); SetWindowIcons(); CreateCursor(); RefreshStdOut(); GetTextSize(); GetBordersDimensions(); InitConsoleWndSize(m_dwColumns); ResizeConsoleWindow(); // ShowHideConsole(); m_bInitializing = FALSE; m_bReloading = FALSE; RefreshScreenBuffer(); ::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns); RepaintWindow(); if (m_dwMasterRepaintInt) ::SetTimer(m_hWnd, TIMER_REPAINT_MASTER, m_dwMasterRepaintInt, NULL); if (m_bStartMinimized) { if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) { m_bHideWindow = TRUE; } else { ::ShowWindow(m_hWnd, SW_MINIMIZE); } } else { ::ShowWindow(m_hWnd, SW_SHOW); } ::SetForegroundWindow(m_hWnd); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::StartShellProcess() { #if 0 if (m_strShell.length() == 0) { TCHAR szComspec[MAX_PATH]; if (::GetEnvironmentVariable(_T("COMSPEC"), szComspec, MAX_PATH) > 0) { m_strShell = szComspec; } else { m_strShell = _T("cmd.exe"); } } tstring strShellCmdLine(m_strShell); if (m_strShellCmdLine.length() > 0) { strShellCmdLine += _T(" "); strShellCmdLine += m_strShellCmdLine; } // strShellCmdLine = "cmd.exe"; // create the console window TCHAR szConsoleTitle[MAX_PATH]; ::AllocConsole(); // we use this to avoid possible problems with multiple console instances running _stprintf(szConsoleTitle, _T("%i"), ::GetCurrentThreadId()); ::SetConsoleTitle(szConsoleTitle); m_hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); while ((m_hWndConsole = ::FindWindow(NULL, szConsoleTitle)) == NULL) ::Sleep(50); ::SetConsoleTitle(m_strWinConsoleTitle.c_str()); #endif // this is a little hack needed to support columns greater than standard 80 RefreshStdOut(); InitConsoleWndSize(80); ResizeConsoleWindow(); #if 0 ::SetConsoleCtrlHandler(Console::CtrlHandler, TRUE); // setup the start up info struct PROCESS_INFORMATION pi; STARTUPINFO si; ::ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); if (!::CreateProcess( NULL, (TCHAR*)strShellCmdLine.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { return FALSE; } if (m_dwHideConsoleTimeout > 0) { ::ShowWindow(m_hWndConsole, SW_MINIMIZE); ::SetTimer(m_hWnd, TIMER_SHOW_HIDE_CONSOLE, m_dwHideConsoleTimeout, NULL); } else { ShowHideConsole(); } // close main thread handle ::CloseHandle(pi.hThread); // set handles m_hQuitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); m_hConsoleProcess = pi.hProcess; #endif return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::RefreshStdOut() { #if 0 if (m_hStdOutFresh) ::CloseHandle(m_hStdOutFresh); m_hStdOutFresh = ::CreateFile(_T("CONOUT$"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::RefreshScreenBuffer() { // if we're initializing, do nothing if (m_bInitializing) return; // ::GetConsoleScreenBufferInfo(m_hStdOutFresh, &m_csbiConsole); SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = (int)m_csbiConsole.srWindow.Top; ::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE); #if 0 if ((m_csbiConsole.srWindow.Right - m_csbiConsole.srWindow.Left + 1 != m_dwColumns) || (m_csbiConsole.srWindow.Bottom - m_csbiConsole.srWindow.Top + 1 != m_dwRows) || (m_csbiConsole.dwSize.Y != m_dwBufferRows)) { m_dwColumns = m_csbiConsole.srWindow.Right - m_csbiConsole.srWindow.Left + 1; m_dwRows = m_csbiConsole.srWindow.Bottom - m_csbiConsole.srWindow.Top + 1; ResizeConsoleWindow(); } COORD coordBufferSize; COORD coordStart; SMALL_RECT srRegion; coordStart.X = 0; coordStart.Y = 0; coordBufferSize.X = m_dwColumns; coordBufferSize.Y = m_dwRows; srRegion.Top = m_csbiConsole.srWindow.Top; srRegion.Left = 0; srRegion.Bottom = m_csbiConsole.srWindow.Top + m_dwRows - 1; srRegion.Right = m_dwColumns - 1; DEL_ARR(m_pScreenBufferNew); m_pScreenBufferNew = new CHAR_INFO[m_dwRows * m_dwColumns]; ::ZeroMemory( m_pScreenBufferNew, m_dwRows * m_dwColumns * sizeof(CHAR_INFO)); for (int i=0; i (DWORD) dwColumns * m_dwBufferRows) { ::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect); ::SetConsoleScreenBufferSize(m_hStdOutFresh, coordConsoleSize); } else if (((DWORD)csbi.dwSize.X < dwColumns) || ((DWORD)csbi.dwSize.Y < m_dwBufferRows) || ((DWORD)(csbi.srWindow.Bottom - csbi.srWindow.Top + 1) != m_dwRows)) { ::SetConsoleScreenBufferSize(m_hStdOutFresh, coordConsoleSize); ::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect); } #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ResizeConsoleWindow() { m_bInitializing = TRUE; if (m_nTextSelection) ClearSelection(); // CONSOLE_SCREEN_BUFFER_INFO csbi; // ::GetConsoleScreenBufferInfo(m_hStdOutFresh, &csbi); // in case buffer rows increased since last resize, and we're not using text buffer if (!m_bUseTextBuffer) m_dwBufferRows = m_dwRows; COORD coordBuffersSize; coordBuffersSize.X = (SHORT)m_dwColumns; coordBuffersSize.Y = (SHORT)m_dwBufferRows; SMALL_RECT srConsoleRect; srConsoleRect.Top = srConsoleRect.Left =0; // srConsoleRect.Right = m_dwColumns - 1; // srConsoleRect.Bottom= m_dwRows - 1; #if 0 // order of setting window size and screen buffer size depends on current and desired dimensions if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) m_dwColumns * m_dwBufferRows) { if (m_bUseTextBuffer && (csbi.dwSize.Y > m_dwBufferRows)) { coordBuffersSize.Y = m_dwBufferRows = csbi.dwSize.Y; } ::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect); ::SetConsoleScreenBufferSize(m_hStdOutFresh, coordBuffersSize); // } else if (((DWORD)csbi.dwSize.X < m_dwColumns) || ((DWORD)csbi.dwSize.Y < m_dwBufferRows) || ((DWORD)(csbi.srWindow.Bottom - csbi.srWindow.Top + 1) != m_dwRows)) { } else if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) m_dwColumns * m_dwBufferRows) { if (csbi.dwSize.Y < m_dwBufferRows) { m_dwBufferRows = coordBuffersSize.Y = csbi.dwSize.Y; } ::SetConsoleScreenBufferSize(m_hStdOutFresh, coordBuffersSize); ::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect); } #endif SetScrollbarStuff(); CalcWindowSize(); SetWindowSizeAndPosition(); CreateOffscreenBuffers(); // if (m_bBitmapBackground) CreateBackgroundBitmap(); } void Console::AllocateBuffer() { // resize screen buffer delete[] m_pScreenBuffer; m_pScreenBuffer = new CHAR_INFO[m_dwRows * m_dwColumns]; m_pScreenBufferNew = new CHAR_INFO[m_dwBufferRows * m_dwColumns]; ::ZeroMemory( m_pScreenBufferNew, m_dwBufferRows * m_dwColumns * sizeof(CHAR_INFO)); m_bInitializing = FALSE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::RepaintWindow() { RECT rect; rect.top = 0; rect.left = 0; rect.bottom = m_nClientHeight; rect.right = m_nClientWidth; #if 0 if (m_bBitmapBackground) { if (m_bRelativeBackground) { ::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY, SRCCOPY); } else { ::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, 0, 0, SRCCOPY); } } else { #endif ::FillRect(m_hdcConsole, &rect, m_hBkBrush); // } DWORD dwX = m_nInsideBorder; DWORD dwY = m_nInsideBorder; DWORD dwOffset = m_csbiConsole.srWindow.Top * m_dwColumns; WORD attrBG; // stuff used for caching int nBkMode = TRANSPARENT; COLORREF crBkColor = RGB(0, 0, 0); COLORREF crTxtColor = RGB(0, 0, 0); // int nNewBkMode = TRANSPARENT; // COLORREF crNewBkColor = RGB(0, 0, 0); // COLORREF crNewTxtColor = RGB(0, 0, 0); bool bTextOut = false; wstring strText(L""); memcpy(m_pScreenBuffer, m_pScreenBufferNew + dwOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns); dwOffset = 0; if (m_nCharWidth > 0) { // fixed pitch font for (DWORD i = 0; i < m_dwRows; ++i) { dwX = m_nInsideBorder; dwY = i*m_nCharHeight + m_nInsideBorder; nBkMode = TRANSPARENT; crBkColor = RGB(0, 0, 0); crTxtColor = RGB(0, 0, 0); bTextOut = false; attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4; // here we decide how to paint text over the backgound if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { ::SetBkMode(m_hdcConsole, TRANSPARENT); nBkMode = TRANSPARENT; } else { ::SetBkMode(m_hdcConsole, OPAQUE); nBkMode = OPAQUE; ::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]); crBkColor = m_arrConsoleColors[attrBG]; } ::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]); crTxtColor = m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]; strText = m_pScreenBuffer[dwOffset].Char.UnicodeChar; ++dwOffset; for (DWORD j = 1; j < m_dwColumns; ++j) { attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4; if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { if (nBkMode != TRANSPARENT) { nBkMode = TRANSPARENT; bTextOut = true; } } else { if (nBkMode != OPAQUE) { nBkMode = OPAQUE; bTextOut = true; } if (crBkColor != m_arrConsoleColors[attrBG]) { crBkColor = m_arrConsoleColors[attrBG]; bTextOut = true; } } if (crTxtColor != (m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF])) { crTxtColor = m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]; bTextOut = true; } if (bTextOut) { ::TextOutW(m_hdcConsole, dwX, dwY, strText.c_str(), strText.length()); dwX += strText.length() * m_nCharWidth; ::SetBkMode(m_hdcConsole, nBkMode); ::SetBkColor(m_hdcConsole, crBkColor); ::SetTextColor(m_hdcConsole, crTxtColor); strText = m_pScreenBuffer[dwOffset].Char.UnicodeChar; } else { strText += m_pScreenBuffer[dwOffset].Char.UnicodeChar; } ++dwOffset; } if (strText.length() > 0) { ::TextOutW(m_hdcConsole, dwX, dwY, strText.c_str(), strText.length()); } } } else { // variable pitch font for (DWORD i = 0; i < m_dwRows; ++i) { dwX = m_nInsideBorder; dwY = i*m_nCharHeight + m_nInsideBorder; for (DWORD j = 0; j < m_dwColumns; ++j) { attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4; // here we decide how to paint text over the backgound if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { ::SetBkMode(m_hdcConsole, TRANSPARENT); } else { ::SetBkMode(m_hdcConsole, OPAQUE); ::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]); } ::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]); ::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwOffset].Char.UnicodeChar), 1); int nWidth; ::GetCharWidth32(m_hdcConsole, m_pScreenBuffer[dwOffset].Char.UnicodeChar, m_pScreenBuffer[dwOffset].Char.UnicodeChar, &nWidth); dwX += nWidth; ++dwOffset; } } } if (m_pCursor) DrawCursor(TRUE); ::InvalidateRect(m_hWnd, NULL, FALSE); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::RepaintWindowChanges() { DWORD dwX = m_nInsideBorder; DWORD dwY = m_nInsideBorder; DWORD dwDestOffset = 0; DWORD dwSrcOffset = m_csbiConsole.srWindow.Top * m_dwColumns; WORD attrBG; if (m_nCharWidth > 0) { // fixed pitch font for (DWORD i = 0; i < m_dwRows; ++i) { dwX = m_nInsideBorder; dwY = i*m_nCharHeight + m_nInsideBorder; for (DWORD j = 0; j < m_dwColumns; ++j) { if (memcmp(&(m_pScreenBuffer[dwDestOffset]), &(m_pScreenBufferNew[dwSrcOffset]), sizeof(CHAR_INFO))) { memcpy(&(m_pScreenBuffer[dwDestOffset]), &(m_pScreenBufferNew[dwSrcOffset]), sizeof(CHAR_INFO)); RECT rect; rect.top = dwY; rect.left = dwX; rect.bottom = dwY + m_nCharHeight; rect.right = dwX + m_nCharWidth; #if 0 if (m_bBitmapBackground) { if (m_bRelativeBackground) { ::BitBlt(m_hdcConsole, dwX, dwY, m_nCharWidth, m_nCharHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX+(int)dwX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY+(int)dwY, SRCCOPY); } else { ::BitBlt(m_hdcConsole, dwX, dwY, m_nCharWidth, m_nCharHeight, m_hdcBackground, dwX, dwY, SRCCOPY); } } else { #endif ::FillRect(m_hdcConsole, &rect, m_hBkBrush); // } attrBG = m_pScreenBuffer[dwDestOffset].Attributes >> 4; // here we decide how to paint text over the backgound if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { ::SetBkMode(m_hdcConsole, TRANSPARENT); } else { ::SetBkMode(m_hdcConsole, OPAQUE); ::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]); } ::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwDestOffset].Attributes & 0xF]); ::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwDestOffset].Char.UnicodeChar), 1); ::InvalidateRect(m_hWnd, &rect, FALSE); } dwX += m_nCharWidth; ++dwDestOffset; ++dwSrcOffset; } } } else { // variable pitch font if (memcmp(m_pScreenBuffer, m_pScreenBufferNew + dwDestOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns)) { memcpy(m_pScreenBuffer, m_pScreenBufferNew + dwDestOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns); RECT rect; rect.top = 0; rect.left = 0; rect.bottom = m_nClientHeight; rect.right = m_nClientWidth; #if 0 if (m_bBitmapBackground) { if (m_bRelativeBackground) { ::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY, SRCCOPY); } else { ::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, 0, 0, SRCCOPY); } } else { #endif ::FillRect(m_hdcConsole, &rect, m_hBkBrush); // } for (DWORD i = 0; i < m_dwRows; ++i) { dwX = m_nInsideBorder; dwY = i*m_nCharHeight + m_nInsideBorder; for (DWORD j = 0; j < m_dwColumns; ++j) { attrBG = m_pScreenBuffer[dwDestOffset].Attributes >> 4; // here we decide how to paint text over the backgound if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { ::SetBkMode(m_hdcConsole, TRANSPARENT); } else { ::SetBkMode(m_hdcConsole, OPAQUE); ::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]); } ::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwDestOffset].Attributes & 0xF]); ::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwDestOffset].Char.UnicodeChar), 1); int nWidth; ::GetCharWidth32(m_hdcConsole, m_pScreenBuffer[dwDestOffset].Char.UnicodeChar, m_pScreenBuffer[dwDestOffset].Char.UnicodeChar, &nWidth); dwX += nWidth; ++dwDestOffset; } } ::InvalidateRect(m_hWnd, NULL, FALSE); } } if (m_pCursor) DrawCursor(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::DrawCursor(BOOL bOnlyCursor) { // first, erase old cursor image if needed if (!bOnlyCursor && m_bCursorVisible) { RECT rectCursorOld; DrawCursorBackground(rectCursorOld); ::InvalidateRect(m_hWnd, &rectCursorOld, FALSE); } #if 0 // now, see if the cursor is visible... CONSOLE_CURSOR_INFO cinf; ::GetConsoleCursorInfo(m_hStdOutFresh, &cinf); m_bCursorVisible = cinf.bVisible; #endif // ... and draw it if (m_bCursorVisible) { #if 0 ::GetConsoleScreenBufferInfo(m_hStdOutFresh, &m_csbiCursor); if (m_csbiCursor.dwCursorPosition.Y < m_csbiCursor.srWindow.Top || m_csbiCursor.dwCursorPosition.Y > m_csbiCursor.srWindow.Bottom) { m_bCursorVisible = FALSE; return; } // set proper cursor offset m_csbiCursor.dwCursorPosition.Y -= m_csbiCursor.srWindow.Top; #endif RECT rectCursor; if (!bOnlyCursor) { DrawCursorBackground(rectCursor); } else { GetCursorRect(rectCursor); } m_pCursor->Draw(&rectCursor); ::InvalidateRect(m_hWnd, &rectCursor, FALSE); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// inline void Console::GetCursorRect(RECT& rectCursor) { ::ZeroMemory(&rectCursor, sizeof(RECT)); if (m_nCharWidth > 0) { // fixed pitch rectCursor.left = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nInsideBorder; rectCursor.top = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nInsideBorder; rectCursor.right = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nCharWidth + m_nInsideBorder; rectCursor.bottom = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nCharHeight + m_nInsideBorder; } else { // variable pitch, we do a little joggling here :-) RECT rectLine; int nLastCharWidth; std::unique_ptr pszLine(new wchar_t[m_csbiCursor.dwCursorPosition.X + 2]); ::ZeroMemory(pszLine.get(), (m_csbiCursor.dwCursorPosition.X + 2)*sizeof(wchar_t)); for (short i = 0; i <= m_csbiCursor.dwCursorPosition.X; ++i) pszLine.get()[i] = m_pScreenBuffer[m_csbiCursor.dwCursorPosition.Y * m_dwColumns + i].Char.UnicodeChar; rectLine.left = rectLine.right = 0; rectLine.top = rectLine.bottom = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight; ::DrawTextW( m_hdcConsole, pszLine.get(), -1, &rectLine, DT_CALCRECT); if (!::GetCharWidth32( m_hdcConsole, pszLine.get()[m_csbiCursor.dwCursorPosition.X], pszLine.get()[m_csbiCursor.dwCursorPosition.X], &nLastCharWidth)) { return; } rectCursor.left = rectLine.right - (DWORD)nLastCharWidth + m_nInsideBorder; rectCursor.top = rectLine.top + m_nInsideBorder; rectCursor.right = rectLine.right + m_nInsideBorder; rectCursor.bottom = rectLine.bottom + m_nInsideBorder; } rectCursor.top -= m_csbiConsole.srWindow.Top * m_nCharHeight; rectCursor.bottom -= m_csbiConsole.srWindow.Top * m_nCharHeight; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// inline void Console::DrawCursorBackground(RECT& rectCursor) { GetCursorRect(rectCursor); if (m_csbiCursor.dwCursorPosition.Y < m_csbiConsole.srWindow.Top || m_csbiCursor.dwCursorPosition.Y >= m_csbiConsole.srWindow.Top + (SHORT) m_dwRows) { return; } DWORD dwOffset = (m_csbiCursor.dwCursorPosition.Y-m_csbiConsole.srWindow.Top)*m_dwColumns + m_csbiCursor.dwCursorPosition.X; WORD attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4; // here we decide how to paint text over the backgound if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) { ::SetBkMode(m_hdcConsole, TRANSPARENT); } else { ::SetBkMode(m_hdcConsole, OPAQUE); ::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]); } ::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]); #if 0 if (m_bBitmapBackground) { if (m_bRelativeBackground) { ::BitBlt( m_hdcConsole, rectCursor.left, rectCursor.top, rectCursor.right - rectCursor.left, rectCursor.bottom - rectCursor.top, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX + rectCursor.left, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY + rectCursor.top, SRCCOPY); } else { ::BitBlt( m_hdcConsole, rectCursor.left, rectCursor.top, rectCursor.right - rectCursor.left, rectCursor.bottom - rectCursor.top, m_hdcBackground, rectCursor.left, rectCursor.top, SRCCOPY); } } else { #endif ::FillRect(m_hdcConsole, &rectCursor, m_hBkBrush); // } ::TextOutW( m_hdcConsole, rectCursor.left, rectCursor.top, &(m_pScreenBuffer[dwOffset].Char.UnicodeChar), 1); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ClearSelection() { m_nTextSelection = TEXT_SELECTION_NONE; m_coordSelOrigin.X = 0; m_coordSelOrigin.Y = 0; ::ZeroMemory(&m_rectSelection, sizeof(RECT)); RepaintWindow(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// DWORD Console::GetChangeRate() { DWORD dwCount = m_dwRows * m_dwColumns; DWORD dwChangedPositions = 0; for (DWORD i = 0; i < dwCount; ++i) { if (m_pScreenBuffer[i].Char.UnicodeChar != m_pScreenBufferNew[i].Char.UnicodeChar) ++dwChangedPositions; } return dwChangedPositions*100/dwCount; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ShowHideWindow() { ::ShowWindowAsync(m_hWnd, m_bHideWindow ? SW_HIDE : SW_SHOW); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ShowHideConsole() { ::ShowWindow(m_hWndConsole, m_bHideConsole ? SW_HIDE : SW_SHOWNORMAL); if (!m_bHideConsole) ::SetForegroundWindow(m_hWndConsole); UpdateHideConsoleMenuItem(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #if 0 void Console::ShowHideConsoleTimeout() { ::KillTimer(m_hWnd, TIMER_SHOW_HIDE_CONSOLE); ShowHideConsole(); } #endif ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ToggleWindowOnTop() { if (m_dwCurrentZOrder == m_dwOriginalZOrder) { m_dwCurrentZOrder = Z_ORDER_ONTOP; } else { m_dwCurrentZOrder = m_dwOriginalZOrder; } HWND hwndZ = 0; switch (m_dwCurrentZOrder) { case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break; case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break; case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break; default : return; } ::SetWindowPos( m_hWnd, hwndZ, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); UpdateOnTopMenuItem(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL Console::HandleMenuCommand(DWORD dwID) { // check if it's one of the main menu commands switch (dwID) { /* case ID_SHOW_README_FILE: ShowReadmeFile(); return FALSE; case ID_ABOUT: About(); return FALSE; */ case ID_COPY: CopyTextToClipboard(); return FALSE; case ID_PASTE: PasteClipoardText(); return FALSE; #if 0 case ID_HIDE_CONSOLE: m_bHideConsole = !m_bHideConsole; ShowHideConsole(); return FALSE; case ID_EDIT_CONFIG_FILE: EditConfigFile(); return FALSE; case ID_RELOAD_SETTINGS: ReloadSettings(); return FALSE; case ID_TOGGLE_ONTOP: ToggleWindowOnTop(); return FALSE; #endif case ID_EXIT_CONSOLE: ::SendMessage(m_hWnd, WM_CLOSE, 0, 0); return FALSE; case SC_MINIMIZE: if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) { m_bHideWindow = !m_bHideWindow; ShowHideWindow(); ::SetForegroundWindow(m_hWnd); return FALSE; } return TRUE; } #if 0 // check if it's one of config file submenu items if ((dwID >= ID_FIRST_XML_FILE) && (dwID <= ID_LAST_XML_FILE)) { TCHAR szFilename[MAX_PATH]; ::ZeroMemory(szFilename, sizeof(szFilename)); ::GetMenuString(m_hConfigFilesMenu, dwID, szFilename, MAX_PATH, MF_BYCOMMAND); m_strConfigFile = tstring(szFilename); if (m_dwReloadNewConfig == RELOAD_NEW_CONFIG_PROMPT) { if (::MessageBox( m_hWndConsole, _T("Load new settings?"), _T("New configuration selected"), MB_YESNO|MB_ICONQUESTION) == IDYES) { ReloadSettings(); } } else if (m_dwReloadNewConfig == RELOAD_NEW_CONFIG_YES) { ReloadSettings(); } return FALSE; } #endif return TRUE; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::UpdateOnTopMenuItem() { #if 0 ::CheckMenuItem(::GetSubMenu(m_hPopupMenu, 0), ID_TOGGLE_ONTOP, MF_BYCOMMAND | ((m_dwCurrentZOrder == Z_ORDER_ONTOP) ? MF_CHECKED : MF_UNCHECKED)); ::CheckMenuItem(m_hSysMenu, ID_TOGGLE_ONTOP, MF_BYCOMMAND | ((m_dwCurrentZOrder == Z_ORDER_ONTOP) ? MF_CHECKED : MF_UNCHECKED)); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::UpdateHideConsoleMenuItem() { #if 0 ::CheckMenuItem(::GetSubMenu(m_hPopupMenu, 0), ID_HIDE_CONSOLE, MF_BYCOMMAND | (m_bHideConsole ? MF_CHECKED : MF_UNCHECKED)); ::CheckMenuItem(m_hSysMenu, ID_HIDE_CONSOLE, MF_BYCOMMAND | (m_bHideConsole ? MF_CHECKED : MF_UNCHECKED)); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::UpdateConfigFilesSubmenu() { #if 0 // populate m_hConfigFilesMenu // first, delete old items while (::GetMenuItemCount(m_hConfigFilesMenu) != 0) ::DeleteMenu(m_hConfigFilesMenu, 0, MF_BYPOSITION); // then, enumerate the files WIN32_FIND_DATA wfd; HANDLE hWfd = NULL; BOOL bMoreFiles = TRUE; DWORD dwID = ID_FIRST_XML_FILE; ::ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA)); // create the search mask... int nBackslashPos = m_strConfigFile.rfind(_TCHAR('\\')); tstring strConfigFileDir(m_strConfigFile.substr(0, nBackslashPos+1)); tstring strSearchFileMask(strConfigFileDir + tstring(_T("*.xml"))); // ... and enumearate files hWfd = ::FindFirstFile(strSearchFileMask.c_str(), &wfd); while ((hWfd != INVALID_HANDLE_VALUE) && bMoreFiles) { MENUITEMINFO mii; TCHAR szFilename[MAX_PATH]; _sntprintf(szFilename, MAX_PATH, _T("%s"), (strConfigFileDir + tstring(wfd.cFileName)).c_str()); ::ZeroMemory(&mii, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_RADIOCHECK | MFT_STRING; mii.wID = dwID++; mii.dwTypeData = szFilename; mii.cch = _tcslen(wfd.cFileName); if (_tcsicmp(szFilename, m_strConfigFile.c_str()) == 0) { mii.fState = MFS_CHECKED; } else { mii.fState = MFS_UNCHECKED; } ::InsertMenuItem(m_hConfigFilesMenu, dwID-ID_FIRST_XML_FILE, TRUE, &mii); bMoreFiles = ::FindNextFile(hWfd, &wfd); } ::FindClose(hWfd); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::CopyTextToClipboard() { int nSelX = (m_rectSelection.left - m_nInsideBorder)/m_nCharWidth; int nSelY = (m_rectSelection.top - m_nInsideBorder)/m_nCharHeight; int nSelColumns = (m_rectSelection.right-m_rectSelection.left)/m_nCharWidth; int nSelRows = (m_rectSelection.bottom-m_rectSelection.top)/m_nCharHeight; // nothing selected, just return if ((nSelColumns == 0) || (nSelRows == 0)) { ClearSelection(); return; } if (!::OpenClipboard(m_hWnd)) { ClearSelection(); return; } ::EmptyClipboard(); HGLOBAL hglbData = ::GlobalAlloc(GMEM_MOVEABLE, (nSelColumns+2)*nSelRows*sizeof(TCHAR)); if (hglbData == NULL) { ::CloseClipboard(); ClearSelection(); return; } // lock the handle and copy the text to the buffer. wchar_t* pszData = (wchar_t*)::GlobalLock(hglbData); if (pszData) { int i; for (i = 0; i < nSelRows; ++i) { for (int j = 0; j < nSelColumns; ++j) { pszData[i*(nSelColumns+2) + j] = m_pScreenBuffer[(nSelY+i)*m_dwColumns + nSelX + j].Char.UnicodeChar; } // at the end of each row we put \r\n (except for the last one where we put \0) pszData[i*(nSelColumns+2) + nSelColumns] = _TCHAR('\r'); pszData[i*(nSelColumns+2) + nSelColumns + 1] = _TCHAR('\n'); } pszData[(i-1)*(nSelColumns+2) + nSelColumns] = _TCHAR('\x0'); } ::GlobalUnlock(hglbData); if (::SetClipboardData(CF_UNICODETEXT, hglbData) == NULL) { // we need to global-free data only if copying failed } ::CloseClipboard(); // !!! No call to GlobalFree here. Next app that uses clipboard will call EmptyClipboard to free the data ClearSelection(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::PasteClipoardText() { if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return; if (::OpenClipboard(m_hWnd)) { HANDLE hData = ::GetClipboardData(CF_UNICODETEXT); SendTextToConsole((wchar_t*)::GlobalLock(hData)); ::GlobalUnlock(hData); ::CloseClipboard(); } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::ShowReadmeFile() { // prepare editor parameters tstring strParams(m_strConfigEditorParams); if (strParams.length() == 0) { // no params, just use the readme file strParams = m_strReadmeFile; } else { tstring::size_type nPos = strParams.find(_T("%f")); if (nPos == tstring::npos) { // no '%f' in editor params, concatenate readme file name strParams += _T(" "); strParams += m_strReadmeFile; } else { // replace '%f' with readme file name strParams = strParams.replace(nPos, 2, m_strReadmeFile); } } ::ShellExecute(NULL, NULL, m_strConfigEditor.c_str(), strParams.c_str(), NULL, SW_SHOWNORMAL); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // About - shows an about dialog void Console::About() { CAboutDlg dlg(m_hWnd); dlg.DoModal(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::SendTextToConsole(const wchar_t *pszText) { if (!pszText || (wcslen(pszText) == 0)) return; BOOL c_state = FALSE; if (m_pCursor) { c_state = (m_pCursor != NULL && m_pCursor->GetState()); m_pCursor->SetState(FALSE); DrawCursor(); } int idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns; RECT rectInval; int cursorX; int cursorY; WORD attr = (WORD)(m_nTextColor + (m_nTextBgColor << 4)); cursorX = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nInsideBorder; cursorY = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nInsideBorder; rectInval.left = cursorX; rectInval.top = cursorY; rectInval.right = cursorX; rectInval.bottom = cursorY + m_nCharHeight; for (; *pszText; pszText++) { int charWidth; ::GetCharWidth32( m_hdcConsole, *pszText, *pszText, &charWidth); if (cursorX + m_nCharWidth > rectInval.right) { rectInval.right = cursorX + m_nCharWidth; } if (cursorX < rectInval.left) { rectInval.left = cursorX; } if (cursorY + m_nCharHeight > rectInval.bottom) { rectInval.bottom = cursorY + m_nCharHeight; } if (cursorY < rectInval.top) { rectInval.top = cursorY; } if (*pszText == 8) { if (m_csbiCursor.dwCursorPosition.X) { m_csbiCursor.dwCursorPosition.X--; cursorX -= m_nCharWidth; idx--; } else if (m_csbiCursor.dwCursorPosition.Y) { if (m_csbiCursor.dwCursorPosition.Y == m_csbiConsole.srWindow.Top) { OnVScroll( SB_LINEUP); } m_csbiCursor.dwCursorPosition.Y--; m_csbiCursor.dwCursorPosition.X = (SHORT)m_dwColumns - 1; cursorX = m_nCharWidth * m_csbiCursor.dwCursorPosition.X; idx--; } } else if (*pszText != '\n' && *pszText != '\r') { m_pScreenBufferNew[ idx].Attributes = attr; m_pScreenBufferNew[ idx].Char.UnicodeChar = *pszText; idx++; cursorX += m_nCharWidth; m_csbiCursor.dwCursorPosition.X++; } if (m_csbiCursor.dwCursorPosition.X >= (SHORT) m_dwColumns || *pszText == '\r' || *pszText == '\n' ) { m_csbiCursor.dwCursorPosition.X = 0; cursorX = m_nInsideBorder; if (*pszText != '\r') { m_csbiCursor.dwCursorPosition.Y++; if (m_csbiCursor.dwCursorPosition.Y >= (SHORT)m_dwBufferRows) { m_csbiCursor.dwCursorPosition.Y--; idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns; ::CopyMemory( m_pScreenBufferNew, m_pScreenBufferNew + m_dwColumns, idx * sizeof( CHAR_INFO)); ::ZeroMemory( m_pScreenBufferNew + idx, m_dwColumns * sizeof( CHAR_INFO)); } else if (m_csbiCursor.dwCursorPosition.Y == m_csbiConsole.srWindow.Top + (SHORT)m_dwRows) { OnVScroll( SB_LINEDOWN); } else { cursorY += m_nCharHeight; } } idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns; } } ::InvalidateRect( m_hWnd, &rectInval, TRUE); ::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL); if (m_pCursor) { m_pCursor->SetState(c_state); } #if 0 HANDLE hStdIn = ::CreateFile(_T("CONIN$"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); DWORD dwTextLen = _tcslen(pszText); DWORD dwTextWritten = 0; INPUT_RECORD* pKeyEvents = new INPUT_RECORD[dwTextLen]; ::ZeroMemory(pKeyEvents, sizeof(INPUT_RECORD)*dwTextLen); for (DWORD i = 0; i < dwTextLen; ++i) { pKeyEvents[i].EventType = KEY_EVENT; pKeyEvents[i].Event.KeyEvent.bKeyDown = TRUE; pKeyEvents[i].Event.KeyEvent.wRepeatCount = 1; pKeyEvents[i].Event.KeyEvent.wVirtualKeyCode = 0; pKeyEvents[i].Event.KeyEvent.wVirtualScanCode = 0; pKeyEvents[i].Event.KeyEvent.uChar.UnicodeChar = pszText[i]; pKeyEvents[i].Event.KeyEvent.dwControlKeyState = 0; } ::WriteConsoleInput(hStdIn, pKeyEvents, dwTextLen, &dwTextWritten); DEL_ARR(pKeyEvents); ::CloseHandle(hStdIn); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// tstring Console::GetFullFilename(const tstring& strFilename) { TCHAR szFilePath[MAX_PATH]; TCHAR* pszFilename; ::ZeroMemory(szFilePath, sizeof(szFilePath)); ::GetFullPathName(strFilename.c_str(), MAX_PATH, szFilePath, &pszFilename); return tstring(szFilePath); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::GetDesktopRect(RECT& rectDesktop) { // if (g_bWin2000) { POINT pt; if (::GetCursorPos(&pt)) { MONITORINFO monitorInfo; monitorInfo.cbSize = sizeof(MONITORINFO); if (GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &monitorInfo)) { rectDesktop = monitorInfo.rcWork; } } else { rectDesktop.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN); rectDesktop.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN); rectDesktop.right = rectDesktop.left + ::GetSystemMetrics(SM_CXVIRTUALSCREEN); rectDesktop.bottom = rectDesktop.top + ::GetSystemMetrics(SM_CYVIRTUALSCREEN); } #if 0 } else { // we keep this for WinNT compatibility rectDesktop.left= 0; rectDesktop.top = 0; rectDesktop.right = ::GetSystemMetrics(SM_CXSCREEN); rectDesktop.bottom = ::GetSystemMetrics(SM_CYSCREEN); RECT rectTaskbar = {0, 0, 0, 0}; HWND hWndTaskbar = ::FindWindow(_T("Shell_TrayWnd"), _T("")); if (hWndTaskbar) { ::GetWindowRect(hWndTaskbar, &rectTaskbar); if ((rectTaskbar.top <= rectDesktop.top) && (rectTaskbar.left <= rectDesktop.left) && (rectTaskbar.right >= rectDesktop.right)) { // top taskbar rectDesktop.top += rectTaskbar.bottom; } else if ((rectTaskbar.top > rectDesktop.top) && (rectTaskbar.left <= rectDesktop.left)) { // bottom taskbar rectDesktop.bottom = rectTaskbar.top; } else if ((rectTaskbar.top <= rectDesktop.top) && (rectTaskbar.left > rectDesktop.left)) { // right taskbar rectDesktop.right = rectTaskbar.left; } else { // left taskbar rectDesktop.left += rectTaskbar.right; } } } #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK Console::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { Console *myself = (Console*) ::GetWindowLongPtr( hwnd, GWLP_USERDATA ); switch (uMsg) { case WM_CREATE: return 0; case WM_PAINT: // paint the window myself->OnPaint(); return 0; case WM_ERASEBKGND: return -1; case WM_SIZE: // set the size and position of the window return 0; case WM_CLOSE: // ::DestroyWindow(myself->m_hWnd); // Probably want to just hide the window if the X is hit. That way it can continue // to update on script output ShowWindow( hwnd, FALSE); return 0; case WM_DESTROY: myself->OnDestroy(); return 0; case WM_NCDESTROY: myself->OnNcDestroy(); return 0; case WM_LBUTTONDOWN: myself->OnLButtonDown((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_LBUTTONUP: myself->OnLButtonUp((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_LBUTTONDBLCLK: myself->OnLButtonDblClick((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_RBUTTONUP: myself->OnRButtonUp((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_MBUTTONDOWN: myself->OnMButtonDown((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_MOUSEMOVE: myself->OnMouseMove((UINT)wParam, MAKEPOINTS(lParam)); return 0; case WM_SETCURSOR: myself->OnSetCursor(LOWORD(lParam), HIWORD(lParam)); ::DefWindowProc(myself->m_hWnd, uMsg, wParam, lParam); return 0; case WM_INITMENUPOPUP: myself->OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), (BOOL)HIWORD(lParam)); return 0; case WM_DROPFILES: myself->OnDropFiles((HDROP)wParam); return 0; case WM_WINDOWPOSCHANGING: myself->OnWindowPosChanging((LPWINDOWPOS)lParam); return 0; case WM_ACTIVATEAPP: myself->OnActivateApp((BOOL)wParam, (DWORD)lParam); return 0; #if 0 case WM_SYSKEYDOWN: case WM_SYSKEYUP: MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); msg.hwnd = myself->m_hWnd; msg.message = uMsg; msg.wParam = wParam; msg.lParam = lParam; ::TranslateMessage(&msg); ::PostMessage(myself->m_hWndConsole, uMsg, wParam, lParam); return 0; #endif case WM_CHAR: myself->OnChar( (WORD) wParam); break; case WM_KEYDOWN: case WM_KEYUP: // case WM_MOUSEWHEEL: // ::PostMessage(myself->m_hWndConsole, uMsg, wParam, lParam); return 0; case WM_VSCROLL: myself->OnVScroll(wParam); return 0; case WM_TIMER: switch (wParam) { case TIMER_REPAINT_CHANGE: case TIMER_REPAINT_MASTER: myself->OnPaintTimer(); return 0; case CURSOR_TIMER: myself->OnCursorTimer(); return 0; #if 0 case TIMER_SHOW_HIDE_CONSOLE: myself->ShowHideConsoleTimeout(); return 0; #endif default: return 1; } case WM_COMMAND: if (myself->OnCommand(wParam, lParam)) { return ::DefWindowProc(hwnd, uMsg, wParam, lParam); } else { return 0; } case WM_SYSCOMMAND: if (myself->OnSysCommand(wParam, lParam)) { return ::DefWindowProc(hwnd, uMsg, wParam, lParam); } else { return 0; } case WM_TRAY_NOTIFY: myself->OnTrayNotify(wParam, lParam); return 0; // case WM_SETTINGCHANGE: // // myself->OnWallpaperChanged((TCHAR*)lParam); // return ::DefWindowProc(hwnd, uMsg, wParam, lParam); case WM_INPUTLANGCHANGEREQUEST: myself->OnInputLangChangeRequest(wParam, lParam); return ::DefWindowProc(hwnd, uMsg, wParam, lParam); // process other messages default: return ::DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // MonitorThread - shell activities monitor DWORD WINAPI Console::MonitorThreadStatic(LPVOID lpParam) { return ((Console*)lpParam)->MonitorThread(); } DWORD Console::MonitorThread() { // HANDLE arrHandles[] = {m_hConsoleProcess, m_hQuitEvent, m_hStdOut}; // HANDLE arrHandles[] = { m_hStdOut}; for (;;) { // Infinite loop #if 0 DWORD dwWait = ::WaitForMultipleObjects(1, arrHandles, FALSE, INFINITE); if (dwWait == WAIT_OBJECT_0) { ::PostMessage(m_hWnd, WM_CLOSE, 0, 0); break; } else if (dwWait == WAIT_OBJECT_0 + 1) { break; } else if (dwWait == WAIT_OBJECT_0 + 2) { #endif AddOutput(); ::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL); // we sleep here for a while, to prevent 'flooding' of m_hStdOut events ::Sleep(m_dwChangeRepaintInt); ::ResetEvent(m_hStdOut); // } } // return 0; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void Console::AddOutput() { DWORD bytesRead; char buf[801]; wchar_t wbuf[801]; ::ReadFile( m_hStdOut, buf, sizeof(buf)/sizeof(wchar_t)-1, &bytesRead, NULL); if (bytesRead == 0) { return; } buf[bytesRead] = 0; MultiByteToWideChar( CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(wbuf[0])); SendTextToConsole( wbuf); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// BOOL WINAPI Console::CtrlHandler(DWORD dwCtrlType) { if ((dwCtrlType == CTRL_C_EVENT) || (dwCtrlType == CTRL_BREAK_EVENT)) { return TRUE; } else { return FALSE; } } /////////////////////////////////////////////////////////////////////////////