mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-24 23:31:07 +00:00
5a5d0e2df4
. Simplify console display functions using StrFormat() . Update TestDebugger that needs StrFormat() now
579 lines
14 KiB
C++
579 lines
14 KiB
C++
/*
|
|
AppleWin : An Apple //e emulator for Windows
|
|
|
|
Copyright (C) 1994-1996, Michael O'Brien
|
|
Copyright (C) 1999-2001, Oliver Schmidt
|
|
Copyright (C) 2002-2005, Tom Charlesworth
|
|
Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski
|
|
|
|
AppleWin 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.
|
|
|
|
AppleWin 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 AppleWin; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/* Description: Debugger
|
|
*
|
|
* Author: Copyright (C) 2006-2010 Michael Pohoreski
|
|
*/
|
|
|
|
// disable warning C4786: symbol greater than 255 character:
|
|
//#pragma warning(disable: 4786)
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "Debugger_Win32.h"
|
|
#include "Debug.h"
|
|
|
|
#include "../Windows/Win32Frame.h"
|
|
#include "../Interface.h"
|
|
#include "../Keyboard.h"
|
|
#include "../Core.h"
|
|
#include "../CPU.h"
|
|
|
|
// Config - Font __________________________________________________________________________________
|
|
// Font
|
|
|
|
//===========================================================================
|
|
static Update_t CmdConfigFontLoad(int nArgs)
|
|
{
|
|
return UPDATE_CONSOLE_DISPLAY;
|
|
}
|
|
|
|
//===========================================================================
|
|
static Update_t CmdConfigFontSave(int nArgs)
|
|
{
|
|
return UPDATE_CONSOLE_DISPLAY;
|
|
}
|
|
|
|
// Only for FONT_DISASM_DEFAULT !
|
|
static void _UpdateWindowFontHeights(int nFontHeight)
|
|
{
|
|
if (nFontHeight)
|
|
{
|
|
int nConsoleTopY = GetConsoleTopPixels(g_nConsoleDisplayLines);
|
|
|
|
int nHeight = 0;
|
|
|
|
if (g_iFontSpacing == FONT_SPACING_CLASSIC)
|
|
{
|
|
nHeight = nFontHeight + 1;
|
|
g_nDisasmDisplayLines = nConsoleTopY / nHeight;
|
|
}
|
|
else
|
|
if (g_iFontSpacing == FONT_SPACING_CLEAN)
|
|
{
|
|
nHeight = nFontHeight;
|
|
g_nDisasmDisplayLines = nConsoleTopY / nHeight;
|
|
}
|
|
else
|
|
if (g_iFontSpacing == FONT_SPACING_COMPRESSED)
|
|
{
|
|
nHeight = nFontHeight - 1;
|
|
g_nDisasmDisplayLines = (nConsoleTopY + nHeight) / nHeight; // Ceil()
|
|
}
|
|
|
|
g_aFontConfig[FONT_DISASM_DEFAULT]._nLineHeight = nHeight;
|
|
|
|
// int nHeightOptimal = (nHeight0 + nHeight1) / 2;
|
|
// int nLinesOptimal = nConsoleTopY / nHeightOptimal;
|
|
// g_nDisasmDisplayLines = nLinesOptimal;
|
|
|
|
WindowUpdateSizes();
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
static Update_t CmdConfigFontMode(int nArgs)
|
|
{
|
|
if (nArgs != 2)
|
|
return Help_Arg_1(CMD_CONFIG_FONT);
|
|
|
|
int nMode = g_aArgs[2].nValue;
|
|
|
|
if ((nMode < 0) || (nMode >= NUM_FONT_SPACING))
|
|
return Help_Arg_1(CMD_CONFIG_FONT);
|
|
|
|
g_iFontSpacing = nMode;
|
|
_UpdateWindowFontHeights(g_aFontConfig[FONT_DISASM_DEFAULT]._nFontHeight);
|
|
|
|
return UPDATE_CONSOLE_DISPLAY | UPDATE_DISASM;
|
|
}
|
|
|
|
//===========================================================================
|
|
bool _CmdConfigFont(int iFont, LPCSTR pFontName, int iPitchFamily, int nFontHeight)
|
|
{
|
|
bool bStatus = false;
|
|
HFONT hFont = (HFONT)0;
|
|
FontConfig_t* pFont = NULL;
|
|
|
|
if (iFont < NUM_FONTS)
|
|
pFont = &g_aFontConfig[iFont];
|
|
else
|
|
return bStatus;
|
|
|
|
if (pFontName)
|
|
{
|
|
// int nFontHeight = g_nFontHeight - 1;
|
|
|
|
int bAntiAlias = (nFontHeight < 14) ? DEFAULT_QUALITY : ANTIALIASED_QUALITY;
|
|
|
|
// Try allow new font
|
|
hFont = CreateFont(
|
|
nFontHeight
|
|
, 0 // Width
|
|
, 0 // Escapement
|
|
, 0 // Orientatin
|
|
, FW_MEDIUM // Weight
|
|
, 0 // Italic
|
|
, 0 // Underline
|
|
, 0 // Strike Out
|
|
, DEFAULT_CHARSET // OEM_CHARSET
|
|
, OUT_DEFAULT_PRECIS
|
|
, CLIP_DEFAULT_PRECIS
|
|
, bAntiAlias // ANTIALIASED_QUALITY // DEFAULT_QUALITY
|
|
, iPitchFamily // HACK: MAGIC #: 4
|
|
, pFontName);
|
|
|
|
if (hFont)
|
|
{
|
|
if (iFont == FONT_DISASM_DEFAULT)
|
|
_UpdateWindowFontHeights(nFontHeight);
|
|
|
|
_tcsncpy(pFont->_sFontName, pFontName, MAX_FONT_NAME - 1);
|
|
pFont->_sFontName[MAX_FONT_NAME - 1] = 0;
|
|
|
|
Win32Frame& win32Frame = Win32Frame::GetWin32Frame();
|
|
|
|
HDC hDC = win32Frame.FrameGetDC();
|
|
|
|
TEXTMETRIC tm;
|
|
GetTextMetrics(hDC, &tm);
|
|
|
|
SIZE size;
|
|
TCHAR sText[] = "W";
|
|
int nLen = 1;
|
|
|
|
int nFontWidthAvg;
|
|
int nFontWidthMax;
|
|
|
|
// if (! (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) // Windows has this bitflag reversed!
|
|
// { // Proportional font?
|
|
// bool bStop = true;
|
|
// }
|
|
|
|
// GetCharWidth32() doesn't work with TrueType Fonts
|
|
if (GetTextExtentPoint32(hDC, sText, nLen, &size))
|
|
{
|
|
nFontWidthAvg = tm.tmAveCharWidth;
|
|
nFontWidthMax = size.cx;
|
|
}
|
|
else
|
|
{
|
|
// Font Name Avg Max "W"
|
|
// Arial 7 8 11
|
|
// Courier 5 32 11
|
|
// Courier New 7 14
|
|
nFontWidthAvg = tm.tmAveCharWidth;
|
|
nFontWidthMax = tm.tmMaxCharWidth;
|
|
}
|
|
|
|
if (!nFontWidthAvg)
|
|
{
|
|
nFontWidthAvg = 7;
|
|
nFontWidthMax = 7;
|
|
}
|
|
|
|
win32Frame.FrameReleaseDC();
|
|
|
|
// DeleteObject( g_hFontDisasm );
|
|
// g_hFontDisasm = hFont;
|
|
pFont->_hFont = hFont;
|
|
|
|
pFont->_nFontWidthAvg = nFontWidthAvg;
|
|
pFont->_nFontWidthMax = nFontWidthMax;
|
|
pFont->_nFontHeight = nFontHeight;
|
|
|
|
bStatus = true;
|
|
}
|
|
}
|
|
return bStatus;
|
|
}
|
|
|
|
void FontsInitialize()
|
|
{
|
|
for (int iFont = 0; iFont < NUM_FONTS; iFont++ )
|
|
{
|
|
g_aFontConfig[ iFont ]._hFont = NULL;
|
|
#if USE_APPLE_FONT
|
|
g_aFontConfig[ iFont ]._nFontHeight = CONSOLE_FONT_HEIGHT;
|
|
g_aFontConfig[ iFont ]._nFontWidthAvg = CONSOLE_FONT_WIDTH;
|
|
g_aFontConfig[ iFont ]._nFontWidthMax = CONSOLE_FONT_WIDTH;
|
|
g_aFontConfig[ iFont ]._nLineHeight = CONSOLE_FONT_HEIGHT;
|
|
#endif
|
|
}
|
|
|
|
#if OLD_FONT
|
|
_CmdConfigFont( FONT_INFO , g_sFontNameInfo , FIXED_PITCH | FF_MODERN , g_nFontHeight ); // DEFAULT_CHARSET
|
|
_CmdConfigFont( FONT_CONSOLE , g_sFontNameConsole, FIXED_PITCH | FF_MODERN , g_nFontHeight ); // DEFAULT_CHARSET
|
|
_CmdConfigFont( FONT_DISASM_DEFAULT, g_sFontNameDisasm , FIXED_PITCH | FF_MODERN , g_nFontHeight ); // OEM_CHARSET
|
|
_CmdConfigFont( FONT_DISASM_BRANCH , g_sFontNameBranch , DEFAULT_PITCH | FF_DECORATIVE, g_nFontHeight+3); // DEFAULT_CHARSET
|
|
#endif
|
|
_UpdateWindowFontHeights( g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontHeight );
|
|
}
|
|
|
|
void FontsDestroy()
|
|
{
|
|
for (int iFont = 0; iFont < NUM_FONTS; iFont++)
|
|
{
|
|
DeleteObject(g_aFontConfig[iFont]._hFont);
|
|
g_aFontConfig[iFont]._hFont = NULL;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdConfigGetFont(int nArgs)
|
|
{
|
|
if (!nArgs)
|
|
{
|
|
for (int iFont = 0; iFont < NUM_FONTS; iFont++)
|
|
{
|
|
ConsoleBufferPushFormat(" Font: %-20s A:%2d M:%2d",
|
|
g_aFontConfig[iFont]._sFontName,
|
|
g_aFontConfig[iFont]._nFontWidthAvg,
|
|
g_aFontConfig[iFont]._nFontWidthMax);
|
|
}
|
|
return ConsoleUpdate();
|
|
}
|
|
|
|
return UPDATE_CONSOLE_DISPLAY;
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdConfigFont(int nArgs)
|
|
{
|
|
int iArg;
|
|
|
|
if (!nArgs)
|
|
return CmdConfigGetFont(nArgs);
|
|
else
|
|
if (nArgs <= 2) // nArgs
|
|
{
|
|
iArg = 1;
|
|
|
|
// FONT * is undocumented, like VERSION *
|
|
if ((!_tcscmp(g_aArgs[iArg].sArg, g_aParameters[PARAM_WILDSTAR].m_sName)) ||
|
|
(!_tcscmp(g_aArgs[iArg].sArg, g_aParameters[PARAM_MEM_SEARCH_WILD].m_sName)))
|
|
{
|
|
ConsoleBufferPushFormat("Lines: %d Font Px: %d Line Px: %d"
|
|
, g_nDisasmDisplayLines
|
|
, g_aFontConfig[FONT_DISASM_DEFAULT]._nFontHeight
|
|
, g_aFontConfig[FONT_DISASM_DEFAULT]._nLineHeight);
|
|
ConsoleBufferToDisplay();
|
|
return UPDATE_CONSOLE_DISPLAY;
|
|
}
|
|
|
|
int iFound;
|
|
int nFound;
|
|
|
|
nFound = FindParam(g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END);
|
|
if (nFound)
|
|
{
|
|
switch (iFound)
|
|
{
|
|
case PARAM_LOAD:
|
|
return CmdConfigFontLoad(nArgs);
|
|
break;
|
|
case PARAM_SAVE:
|
|
return CmdConfigFontSave(nArgs);
|
|
break;
|
|
// TODO: FONT SIZE #
|
|
// TODO: AA {ON|OFF}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
nFound = FindParam(g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_FONT_BEGIN, _PARAM_FONT_END);
|
|
if (nFound)
|
|
{
|
|
if (iFound == PARAM_FONT_MODE)
|
|
return CmdConfigFontMode(nArgs);
|
|
}
|
|
|
|
return CmdConfigSetFont(nArgs);
|
|
}
|
|
|
|
return Help_Arg_1(CMD_CONFIG_FONT);
|
|
}
|
|
|
|
//===========================================================================
|
|
void DebuggerMouseClick(int x, int y)
|
|
{
|
|
if (g_nAppMode != MODE_DEBUG)
|
|
return;
|
|
|
|
KeybUpdateCtrlShiftStatus();
|
|
int iAltCtrlShift = 0;
|
|
iAltCtrlShift |= KeybGetAltStatus() ? 1 << 0 : 0;
|
|
iAltCtrlShift |= KeybGetCtrlStatus() ? 1 << 1 : 0;
|
|
iAltCtrlShift |= KeybGetShiftStatus() ? 1 << 2 : 0;
|
|
|
|
// GH#462 disasm click #
|
|
if (iAltCtrlShift != g_bConfigDisasmClick)
|
|
return;
|
|
|
|
Win32Frame& win32Frame = Win32Frame::GetWin32Frame();
|
|
|
|
int nFontWidth = g_aFontConfig[FONT_DISASM_DEFAULT]._nFontWidthAvg * win32Frame.GetViewportScale();
|
|
int nFontHeight = g_aFontConfig[FONT_DISASM_DEFAULT]._nLineHeight * win32Frame.GetViewportScale();
|
|
|
|
// do picking
|
|
|
|
const int nOffsetX = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetX() : win32Frame.Get3DBorderWidth();
|
|
const int nOffsetY = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetY() : win32Frame.Get3DBorderHeight();
|
|
|
|
const int nOffsetInScreenX = x - nOffsetX;
|
|
const int nOffsetInScreenY = y - nOffsetY;
|
|
|
|
if (nOffsetInScreenX < 0 || nOffsetInScreenY < 0)
|
|
return;
|
|
|
|
int cx = nOffsetInScreenX / nFontWidth;
|
|
int cy = nOffsetInScreenY / nFontHeight;
|
|
|
|
#if _DEBUG
|
|
ConsoleDisplayPushFormat("x:%d y:%d cx:%d cy:%d", x, y, cx, cy);
|
|
DebugDisplay();
|
|
#endif
|
|
|
|
if (g_iWindowThis == WINDOW_CODE)
|
|
{
|
|
// Display_AssemblyLine -- need Tabs
|
|
|
|
if (g_bConfigDisasmAddressView)
|
|
{
|
|
// HACK: hard-coded from DrawDisassemblyLine::aTabs[] !!!
|
|
if (cx < 4) // ####
|
|
{
|
|
g_bConfigDisasmAddressView ^= true;
|
|
DebugDisplay();
|
|
}
|
|
else
|
|
if (cx == 4) // :
|
|
{
|
|
g_bConfigDisasmAddressColon ^= true;
|
|
DebugDisplay();
|
|
}
|
|
else // AD 00 00
|
|
if ((cx > 4) && (cx <= 13))
|
|
{
|
|
g_bConfigDisasmOpcodesView ^= true;
|
|
DebugDisplay();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (cx == 0) // :
|
|
{
|
|
// Three-way state
|
|
// "addr:"
|
|
// ":"
|
|
// " "
|
|
g_bConfigDisasmAddressColon ^= true;
|
|
if (g_bConfigDisasmAddressColon)
|
|
{
|
|
g_bConfigDisasmAddressView ^= true;
|
|
}
|
|
DebugDisplay();
|
|
}
|
|
else
|
|
if ((cx > 0) & (cx <= 13))
|
|
{
|
|
g_bConfigDisasmOpcodesView ^= true;
|
|
DebugDisplay();
|
|
}
|
|
}
|
|
// Click on PC inside reg window?
|
|
if ((cx >= 51) && (cx <= 60))
|
|
{
|
|
if (cy == 3)
|
|
{
|
|
CmdCursorJumpPC(CURSOR_ALIGN_CENTER);
|
|
DebugDisplay();
|
|
}
|
|
else
|
|
if (cy == 4 || cy == 5)
|
|
{
|
|
int iFlag = -1;
|
|
int nFlag = _6502_NUM_FLAGS;
|
|
|
|
while (nFlag-- > 0)
|
|
{
|
|
// TODO: magic number instead of DrawFlags() DISPLAY_FLAG_COLUMN, rect.left += ((2 + _6502_NUM_FLAGS) * nSpacerWidth);
|
|
// BP_SRC_FLAG_C is 6, cx 60 --> 0
|
|
// ...
|
|
// BP_SRC_FLAG_N is 13, cx 53 --> 7
|
|
if (cx == (53 + nFlag))
|
|
{
|
|
iFlag = 7 - nFlag;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iFlag >= 0)
|
|
{
|
|
regs.ps ^= (1 << iFlag);
|
|
DebugDisplay();
|
|
}
|
|
}
|
|
else // Click on stack
|
|
if (cy > 3)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
Update_t CmdConfigSetFont(int nArgs)
|
|
{
|
|
#if OLD_FONT
|
|
HFONT hFont = (HFONT)0;
|
|
TCHAR* pFontName = NULL;
|
|
int nHeight = g_nFontHeight;
|
|
int iFontTarget = FONT_DISASM_DEFAULT;
|
|
int iFontPitch = FIXED_PITCH | FF_MODERN;
|
|
// int iFontMode =
|
|
bool bHaveTarget = false;
|
|
bool bHaveFont = false;
|
|
|
|
if (!nArgs)
|
|
{ // reset to defaut font
|
|
pFontName = g_sFontNameDefault;
|
|
}
|
|
else
|
|
if (nArgs <= 3)
|
|
{
|
|
int iArg = 1;
|
|
pFontName = g_aArgs[1].sArg;
|
|
|
|
// [DISASM|INFO|CONSOLE] "FontName" [#]
|
|
// "FontName" can be either arg 1 or 2
|
|
|
|
int iFound;
|
|
int nFound = FindParam(g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_WINDOW_BEGIN, _PARAM_WINDOW_END);
|
|
if (nFound)
|
|
{
|
|
switch (iFound)
|
|
{
|
|
case PARAM_DISASM: iFontTarget = FONT_DISASM_DEFAULT; iFontPitch = FIXED_PITCH | FF_MODERN; bHaveTarget = true; break;
|
|
case PARAM_INFO: iFontTarget = FONT_INFO; iFontPitch = FIXED_PITCH | FF_MODERN; bHaveTarget = true; break;
|
|
case PARAM_CONSOLE: iFontTarget = FONT_CONSOLE; iFontPitch = DEFAULT_PITCH | FF_DECORATIVE; bHaveTarget = true; break;
|
|
default:
|
|
if (g_aArgs[2].bType != TOKEN_QUOTE_DOUBLE)
|
|
return Help_Arg_1(CMD_CONFIG_FONT);
|
|
break;
|
|
}
|
|
if (bHaveTarget)
|
|
{
|
|
pFontName = g_aArgs[2].sArg;
|
|
}
|
|
}
|
|
else
|
|
if (nArgs == 2)
|
|
{
|
|
nHeight = atoi(g_aArgs[2].sArg);
|
|
if ((nHeight < 6) || (nHeight > 36))
|
|
nHeight = g_nFontHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Help_Arg_1(CMD_CONFIG_FONT);
|
|
}
|
|
|
|
if (!_CmdConfigFont(iFontTarget, pFontName, iFontPitch, nHeight))
|
|
{
|
|
}
|
|
#endif
|
|
return UPDATE_ALL;
|
|
}
|
|
|
|
void Util_CopyTextToClipboard(const size_t nSize, const char* pText)
|
|
{
|
|
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, nSize + 1);
|
|
memcpy(GlobalLock(hMem), pText, nSize + 1);
|
|
GlobalUnlock(hMem);
|
|
|
|
OpenClipboard(0);
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_TEXT, hMem);
|
|
CloseClipboard();
|
|
|
|
// GlobalFree() ??
|
|
}
|
|
|
|
void ProcessClipboardCommands()
|
|
{
|
|
// Support Clipboard (paste)
|
|
if (!IsClipboardFormatAvailable(CF_TEXT))
|
|
return;
|
|
|
|
if (!OpenClipboard(GetFrame().g_hFrameWindow))
|
|
return;
|
|
|
|
HGLOBAL hClipboard;
|
|
LPTSTR pData;
|
|
|
|
hClipboard = GetClipboardData(CF_TEXT);
|
|
if (hClipboard != NULL)
|
|
{
|
|
pData = (char*)GlobalLock(hClipboard);
|
|
if (pData != NULL)
|
|
{
|
|
LPTSTR pSrc = pData;
|
|
char c;
|
|
|
|
while (true)
|
|
{
|
|
c = *pSrc++;
|
|
|
|
if (!c)
|
|
break;
|
|
|
|
if (c == CHAR_CR)
|
|
{
|
|
// Eat char
|
|
}
|
|
else
|
|
if (c == CHAR_LF)
|
|
{
|
|
DebuggerProcessCommand(true);
|
|
}
|
|
else
|
|
{
|
|
// If we didn't want verbatim, we could do:
|
|
// DebuggerInputConsoleChar( c );
|
|
if ((c >= CHAR_SPACE) && (c <= 126)) // HACK MAGIC # 32 -> ' ', # 126
|
|
ConsoleInputChar(c);
|
|
}
|
|
}
|
|
GlobalUnlock(hClipboard);
|
|
}
|
|
}
|
|
CloseClipboard();
|
|
|
|
UpdateDisplay(UPDATE_CONSOLE_DISPLAY);
|
|
}
|