mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Replaced Windows console with freeware console implementation. Activate in windowed mode with \ Added error and quit if JA2 started in window mode in >16bpp color depth Fix to enemy sector investigation: Was deducting from redshirts when elites investigated Fix AWOL militia (need additional fix to prevent them from being redistributed during after reinforcements) Fix to tanks to add them in their original spot when a new one cannot be found. Should modify to remove old wreckage in this case. AI no longer tries to fire mortar when no room for it Tanks no longer try to throw knives git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1030 3b4a5df2-a311-0410-b5c6-a8a6f20db521
4561 lines
139 KiB
C++
4561 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_WTEXT);
|
|
FILE *fp = _fdopen( hConHandle, "w" );
|
|
*stdout = *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(TCHAR* pszConfigPath) {
|
|
|
|
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
|
|
wcout << "Test" << endl;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
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)
|
|
{
|
|
if (Input.length() > 0)
|
|
{
|
|
wchar_t last = Input[ Input.length() - 1];
|
|
|
|
text[0] = 8;
|
|
text[1] = L' ';
|
|
text[2] = 8;
|
|
text[3] = 0;
|
|
|
|
Input.resize( Input.length() - 1);
|
|
|
|
if (last == '\n')
|
|
{
|
|
int cx = Input.rfind( '\n') + 1;
|
|
cx = Input.length() - cx;
|
|
SendTextToConsole( text);
|
|
m_csbiCursor.dwCursorPosition.X = cx;
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if (myChar == '\r')
|
|
{
|
|
text[0] = '\n';
|
|
text[1] = '\r';
|
|
text[2] = 0;
|
|
Input += '\n';
|
|
}
|
|
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 = 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);
|
|
|
|
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;
|
|
wchar_t buf[801];
|
|
::ReadFile( m_hStdOut, buf, sizeof(buf)/sizeof(wchar_t)-1, &bytesRead, NULL);
|
|
if (bytesRead == 0) {
|
|
return;
|
|
}
|
|
buf[bytesRead/sizeof(wchar_t)] = 0;
|
|
SendTextToConsole( buf);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI Console::CtrlHandler(DWORD dwCtrlType) {
|
|
if ((dwCtrlType == CTRL_C_EVENT) || (dwCtrlType == CTRL_BREAK_EVENT)) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|