📄 term.c
字号:
*/
termSelectWordExtend(&xpos, &ypos, inNextChar);
if (xpos == term.selectTo.x && ypos == term.selectTo.y)
/* No change in selection, nothing else to do
*/
return;
if (term.haveSelection)
/* Redraw the part of the selection that changed
*/
selectInvalidate(term.selectTo.y, term.selectTo.x, ypos, xpos);
/* Record the new selection
*/
term.haveSelection = TRUE;
term.selectTo.x = xpos;
term.selectTo.y = ypos;
}
/* Return whether or not there is a selection defined
*/
static BOOL termSelectCheck(void)
{
term.haveSelection = term.selectFrom.x != term.selectTo.x
|| term.selectFrom.y != term.selectTo.y;
return term.haveSelection;
}
/* Convert terminal window pixel positions to terminal character
* positions. Return if the mouse was actually over the next
* character cell.
*
* Args:
* xpos - point to x-position (pixels) in terminal window
* ypos - point to y-position (pixels) in terminal window
*/
static BOOL termSelectAdjustPos(int* xpos, int* ypos)
{
BOOL inNextChar = (*xpos % term.charSize.cx) != 0;
/* Convert x-pos from pixels to characters
*/
*xpos /= term.charSize.cx;
if (*xpos < 0)
*xpos = 0;
else if (*xpos > term.winSize.cx)
*xpos = term.winSize.cx;
/* Convert y-pos from pixels to characters
*/
*ypos /= term.charSize.cy;
if (*ypos < 0)
*ypos = 0;
else if (*ypos > term.winSize.cy)
*ypos = term.winSize.cy;
return inNextChar;
}
/* Start a timer to automatically extend the selection when the mouse
* is above or below the terminal window
*/
static void termSelectStartTimer(void)
{
if (termTimerId == 0)
termTimerId = SetTimer(termWnd, ID_TERM_TIMER, 50, NULL);
}
/* Stop the timer that is used to extend the selection
*/
static void termSelectStopTimer(void)
{
if (termTimerId == 0)
return;
KillTimer(termWnd, ID_TERM_TIMER);
termTimerId = 0;
}
/* Return whether or not the user is currently performing a selection
*/
BOOL termSelectInProgress(void)
{
return GetCapture() == termWnd;
}
/* Return whether or not there currently is a selection
*/
BOOL termHaveSelection(void)
{
return term.haveSelection;
}
/***********************
* TERMINAL MANAGEMENT *
***********************/
/* Return handle of the terminal window
*/
HWND termGetWnd(void)
{
return termWnd;
}
/* Build a caret. This should really be quite easy (according to the
* Microsoft documentation), but for some reason Windows 3.1 gives the
* caret a random color when we use our own palette.
*
* After days of pulling what little hair I have left out of my head,
* I arrived at this wonderfully elegant, and intuitively obvious
* code. Read it and weep.
*
* I would comment the code, but I do not have the stomach for it.
*/
static void termMakeCaretBitmap(void)
{
HDC dc;
HDC memDc;
HBRUSH brush;
HBRUSH oldBrush;
HBITMAP oldBitmap;
HPALETTE oldPalette;
if (term.caretBitmap != NULL)
DeleteObject(term.caretBitmap);
switch (cursorStyle)
{
case cursorBlock:
SetRect(&term.cursorRect, 0, 0, term.charSize.cx, term.charSize.cy);
break;
case cursorVertLine:
SetRect(&term.cursorRect, 0, 0, 2, term.charSize.cy);
break;
case cursorUnderLine:
SetRect(&term.cursorRect, 0, term.charSize.cy-2, term.charSize.cx, 2);
break;
}
dc = GetDC(termWnd);
term.caretBitmap
= CreateCompatibleBitmap(dc, term.cursorRect.right, term.cursorRect.bottom);
memDc = CreateCompatibleDC(dc);
oldBitmap = (HBITMAP)SelectObject(memDc, term.caretBitmap);
if (termHasPalette) {
oldPalette = SelectPalette(memDc, termPalette, 0);
RealizePalette(memDc);
brush = CreateSolidBrush(PALETTEINDEX(BOLD+White));
} else
brush = CreateSolidBrush(colors[BOLD+White]);
oldBrush = (HBRUSH)SelectObject(memDc, brush);
PatBlt(memDc, 0, 0, term.cursorRect.right, term.cursorRect.bottom, PATCOPY);
SelectObject(memDc, oldBrush);
DeleteObject(brush);
if (termHasPalette)
SelectObject(memDc, oldPalette);
SelectObject(memDc, oldBitmap);
DeleteDC(memDc);
ReleaseDC(termWnd, dc);
}
/* Set the font used to draw the terminal. Propagate the window
* resize up to the application window.
*/
void termSetFont(void)
{
TEXTMETRIC tm; /* get metrics of new terminal font */
/* Create the font that is used in the terminal window
*/
if (term.font != 0)
DeleteObject(term.font);
fontCreate (termWnd, &tm, &term.font, &term.oemfont);
term.fontCharSet = tm.tmCharSet;
term.charSize.cy = tm.tmHeight;
term.charSize.cx = tm.tmAveCharWidth;
/* Build a new caret with the new character size
*/
termMakeCaretBitmap();
/* Tell our parent window how big we want to be
*/
telnetTerminalSize(term.winSize.cx * term.charSize.cx + vscrollWidth,
term.winSize.cy * term.charSize.cy);
/* Now make ourselves the requested size. It seems that if we do
* not say fRepaint = TRUE the scrollbar is not redrawn???!?!
*
* I LOVE WINDOWS
*/
MoveWindow(termWnd, 0, 0,
term.winSize.cx * term.charSize.cx + vscrollWidth,
term.winSize.cy * term.charSize.cy, TRUE);
/* Make sure the entire client area is redrawn with the new font
*/
InvalidateRect(termWnd, NULL, FALSE);
}
static BOOL extractGeometry(char* str, SIZE* size, SIZE* pos)
{
int num;
char xrel, yrel;
num = sscanf(str, "%dx%d%c%d%c%d",
&size->cx, &size->cy, &xrel, &pos->cx, &yrel, &pos->cy);
if (num == 6
&& (xrel == '-' || xrel == '+')
&& (yrel == '-' || yrel == '+')) {
if (xrel == '-')
pos->cx = -pos->cx;
if (yrel == '-')
pos->cy = -pos->cy;
return TRUE;
}
if (num < 2) {
size->cx = 80;
size->cy = 25;
}
pos->cx = 0;
pos->cy = 0;
return FALSE;
}
// Khader
/* Checks if windows size is according to defined limits
*/
void termCheckSizeLimits()
{
/* Limit the terminal width to TERM_MIN_X .. TERM_MAX_X
*/
if (term.winSize.cx < TERM_MIN_X) /* Khader - replaced consts with defines */
term.winSize.cx = TERM_MIN_X;
if (term.winSize.cx > TERM_MAX_X)
term.winSize.cx = TERM_MAX_X;
/* Limit the terminal height to TERM_MIN_Y .. TERM_MAX_Y
*/
if (term.winSize.cy < TERM_MIN_Y)
term.winSize.cy = TERM_MIN_Y;
if (term.winSize.cy > TERM_MAX_Y)
term.winSize.cy = TERM_MAX_Y;
}
/* Set the geometry of the terminal window (in characters)
*
* Args:
* str - new window geometry in form WxH or WxH+X+Y
*/
void termSetGeometry(char* str)
{
/* Extract the size and position from str
*/
term.useInitPos = extractGeometry(str, &term.winSize, &term.winInitPos);
termCheckSizeLimits(); // Khader
/* Do not save the window geometry in the .INI file if set via the
* command line
*/
useIniGeometry = FALSE;
}
/* We are about to receive window focus - realise our palette and
* force a repaint of the window if necessary
*
* Return the number of changes
*/
static int termPaletteChanged(void)
{
HDC dc; /* terminal window device context */
HPALETTE oldPalette; /* remember original palette in dc */
UINT numChanges; /* number of changes in mapping system
* palette since our palette last
* realised */
if (!termHasPalette)
/* We are not using a palette, nothing to do
*/
return 0;
/* Realise our logical palette in the system palette and determine
* if there are any changes in the mapping
*/
dc = GetDC(termWnd);
oldPalette = SelectPalette(dc, termPalette, FALSE);
numChanges = RealizePalette(dc);
SelectPalette(dc, oldPalette, FALSE);
ReleaseDC(termWnd, dc);
/* There were changes in the palette mapping - repaint the window
*/
if (numChanges > 0)
InvalidateRect(termWnd, NULL, FALSE);
/* Return the number of changes in the mapping
*/
return (int)numChanges;
}
/* Build a palette for our terminal window
*/
static void termBuildPalette(void)
{
NPLOGPALETTE palette;
int idx;
HANDLE hnd = LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE)
+ PaletteSize * sizeof(PALETTEENTRY));
if (!hnd)
return;
palette = (NPLOGPALETTE)LocalLock(hnd);
palette->palVersion = 0x300;
palette->palNumEntries = PaletteSize;
for (idx = 0; idx < PaletteSize; idx++) {
COLORREF color = colors[idx];
palette->palPalEntry[idx].peRed = GetRValue(color);
palette->palPalEntry[idx].peGreen = GetGValue(color);
palette->palPalEntry[idx].peBlue = GetBValue(color);
palette->palPalEntry[idx].peFlags = 0;
}
termPalette = CreatePalette((LPLOGPALETTE)palette);
LocalUnlock((HLOCAL)palette);
LocalFree(hnd);
}
/* Set the attribute to be used for blank characters
*/
void termSetBlankAttr(int attr)
{
term.blankAttr = (unsigned char)attr;
}
/* Set the application window title
*/
void termSetTitle(char* title)
{
strcpy(term.title, title);
telnetSetTitle();
}
/* Return the application window title
*/
char* termGetTitle()
{
return term.title;
}
/* Return whether or not there is a application window title set
*/
BOOL termHasTitle()
{
return term.title[0] != '\0';
}
/* Scroll the window a number of lines. Positive values scroll lines
* up.
*
* Args:
* numLines - the number of lines to scroll
*/
static void termDoScroll(int numLines)
{
if (!numLines)
/* Nothing to do
*/
return;
if (abs(numLines) >= term.winSize.cy)
/* Scrolling replaces the entire window - repaint it all
*/
InvalidateRect(termWnd, NULL, TRUE);
else
/* Scrolling retains some of the window
*/
winScrollWindow(numLines);
/* Update the top visible line and the history scrollbar
*/
term.topVisibleLine += numLines;
SetScrollPos(termWnd, SB_VERT, term.topVisibleLine, TRUE);
}
/* Try scrolling the terminal a number of lines. Positive values
* scroll lines up.
*
* Args:
* numLines - the number of lines to scroll
*/
static void termTryScroll(int numLines)
{
if (numLines > 0) {
/* Scrolling lines up
*/
if (term.topVisibleLine < winTerminalTopLine()) {
/* We can scroll lines up. Make sure we do not scroll
* more lines than exist.
*/
if (term.topVisibleLine + numLines < winTerminalTopLine())
termDoScroll(numLines);
else
termDoScroll(winTerminalTopLine() - term.topVisibleLine);
}
} else {
/* Scrolling lines down
*/
if (term.topVisibleLine > 0) {
/* We can scroll lines down. Make sure wr do not scroll
* more lines than exist.
*/
if (term.topVisibleLine + numLines >= 0)
termDoScroll(numLines);
else
termDoScroll(-term.topVisibleLine);
}
}
}
/* User moved the history scrollbar. Scroll the terminal window.
*
* Args:
* code - the type of scroll performed
* pos - the scrollbar position
*/
static void termUseScrollbar(UINT code, UINT pos)
{
if (term.numLinesUsed <= term.winSize.cy)
/* Cannot scroll if we have used less lines than the height of
* the window.
*/
return;
switch (code) {
case SB_BOTTOM:
termDoScroll(winTerminalTopLine() - term.topVisibleLine);
break;
case SB_ENDSCROLL:
break;
case SB_LINEDOWN:
termTryScroll(1);
break;
case SB_LINEUP:
termTryScroll(-1);
break;
case SB_PAGEDOWN:
termTryScroll(term.winSize.cy);
break;
case SB_PAGEUP:
termTryScroll(-term.winSize.cy);
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
if ((int)pos > winTerminalTopLine())
pos = winTerminalTopLine();
termDoScroll((int)pos - term.topVisibleLine);
break;
case SB_TOP:
termDoScroll(-term.topVisibleLine);
break;
}
/* Redraw the caret at the correct position
*/
winCaretPos(term.cursor.x, term.cursor.y);
}
/* Scroll the terminal to the bottom of the history
*/
void termScrollToBottom()
{
if (term.numLinesUsed > term.winSize.cy)
termDoScroll(winTerminalTopLine() - term.topVisibleLine);
}
/* Toggle whether or not terminal output forces a scroll to bottom
*/
void termToggleBottomOnOutput()
{
bottomOnOutput = !bottomOnOutput;
}
/* Return whether or not terminal output forces a scroll to bottom
*/
BOOL termBottomOnOutput()
{
return bottomOnOutput;
}
/* Toggle the state of auto-copy on selection
*/
void termToggleAutoCopy()
{
autoCopy = !autoCopy;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -