Files
source/Console/Console.cpp
T
Overhaul 8e75433dd1 Militia and friendly AI now mark mines for OUR side.
Related to above, militia deadlock fixed
Crash if console hasn't been brought up when text is sent to it fixed

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1058 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-07-15 20:34:43 +00:00

4571 lines
139 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// 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 <atlbase.h>
#include <tchar.h>
#include <msxml.h>
#include <shellapi.h>
#include <commctrl.h>
#include <memory>
#include <io.h>
#include <fcntl.h>
#include <iostream>
#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))) {
nCurrentPos += nDelta;
SMALL_RECT sr;
sr.Top = 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) {
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);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
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;
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,
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 {
int 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<m_dwRows*m_dwColumns; i++) { m_pScreenBufferNew[i].Char.AsciiChar = '0' + i%10; m_pScreenBufferNew[i].Attributes = 15; }
::ReadConsoleOutput(m_hStdOutFresh, m_pScreenBufferNew, coordBufferSize, coordStart, &srRegion);
// set console window title
TCHAR szWinConsoleTitle[MAX_PATH+1];
::GetConsoleTitle(szWinConsoleTitle, MAX_PATH);
tstring strWinConsoleTitle(szWinConsoleTitle);
tstring strConsoleTitle(_T(""));
// Here we decide about updating Console window title.
// There are 2 possibilities:
if (m_strWinConsoleTitle.compare(0, m_strWinConsoleTitle.length(), strWinConsoleTitle, 0, m_strWinConsoleTitle.length()) == 0) {
// 1. Windows console title starts with the original title, just see if
// windows titles differ, and if they do, update it.
if ((m_strWindowTitle.length() == 0) &&
(strWinConsoleTitle[m_strWinConsoleTitle.length()] == ' ') &&
(strWinConsoleTitle[m_strWinConsoleTitle.length()+1] == '-')) {
strConsoleTitle = strWinConsoleTitle.substr(m_strWinConsoleTitle.length()+3);
} else {
strConsoleTitle = m_strWindowTitle + strWinConsoleTitle.substr(m_strWinConsoleTitle.length());
}
} else {
// 2. Windows console title is completely changed. To set Console title,
// we need to get Windows console title and concatenate it to our
// original Console title (if it changed since the last update)
if (m_strWindowTitle.length() == 0) {
strConsoleTitle = strWinConsoleTitle;
} else {
strConsoleTitle = m_strWindowTitle + tstring(_T(" - ")) + strWinConsoleTitle;
}
}
if (m_strWindowTitleCurrent.compare(strConsoleTitle) != 0) {
m_strWindowTitleCurrent = strConsoleTitle;
::SetWindowText(m_hWnd, m_strWindowTitleCurrent.c_str());
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::InitConsoleWndSize(DWORD dwColumns) {
if (m_nTextSelection) ClearSelection();
// get max console size
// COORD coordMaxSize;
// coordMaxSize = ::GetLargestConsoleWindowSize(m_hStdOutFresh);
// calc max window size
RECT rectDesktop;
GetDesktopRect(rectDesktop);
DWORD dwMaxColumns = (rectDesktop.right - rectDesktop.left - 2*m_nInsideBorder - 2*m_nXBorderSize - m_nScrollbarWidth)/m_nCharWidth;
DWORD dwMaxRows = (rectDesktop.bottom - rectDesktop.top - 2*m_nInsideBorder - m_nYBorderSize - m_nCaptionSize)/m_nCharHeight;
// if (m_dwColumns == 0) m_dwColumns = coordMaxSize.X < dwMaxColumns ? coordMaxSize.X : dwMaxColumns;
// if (m_dwRows == 0) m_dwRows = coordMaxSize.Y < dwMaxRows ? coordMaxSize.Y : dwMaxRows;
if (m_dwColumns == 0) m_dwColumns = dwMaxColumns;
if (m_dwRows == 0) m_dwRows = dwMaxRows;
if (m_dwBufferRows < m_dwRows) m_dwBufferRows = m_dwRows;
COORD coordConsoleSize;
coordConsoleSize.X = (SHORT)dwColumns;
coordConsoleSize.Y = (SHORT)m_dwBufferRows;
SMALL_RECT srConsoleRect;
srConsoleRect.Top = srConsoleRect.Left =0;
srConsoleRect.Right = dwColumns - 1;
srConsoleRect.Bottom= m_dwRows - 1;
#if 0
CONSOLE_SCREEN_BUFFER_INFO csbi;
::GetConsoleScreenBufferInfo(m_hStdOutFresh, &csbi);
if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (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;
auto_ptr<wchar_t> pszLine(new wchar_t[m_csbiCursor.dwCursorPosition.X + 2]);
::ZeroMemory(pszLine.get(), (m_csbiCursor.dwCursorPosition.X + 2)*sizeof(wchar_t));
for (DWORD 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 + 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;
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,
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);
{
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 {
int 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;
int attr = 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 = 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 >= 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 >= 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 + 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( 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};
while (1) {
DWORD dwWait = ::WaitForMultipleObjects(1, arrHandles, FALSE, INFINITE);
#if 0
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;
}
}
/////////////////////////////////////////////////////////////////////////////