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