⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 term.c

📁 dtelent是开源的开发项目
💻 C
📖 第 1 页 / 共 5 页
字号:
/* term.c
 * Copyright (c) 1997 David Cole
 *
 * Control and manage the terminal window
 */
#include <windows.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>

#include "platform.h"
#include "utils.h"
#include "term.h"
#include "termwin.h"
#include "lines.h"
#include "dtelnet.h"
#include "socket.h"
#include "raw.h"
#include "font.h"
#include "status.h"
#include "emul.h"
#include "log.h"
/* Fred. We need the bs2Del flag of the current session
 */
#include "connect.h"

static char* termWinClass = "DTermWClass";

Terminal term;			/* The terminal */

static HWND termWnd;		/* terminal window handle */
static BOOL termHasPalette;	/* can we support palettes? */
static HPALETTE termPalette;	/* the palette for the window */
static UINT termTimerId;	/* selection scrolling timer */
static BOOL haveCaret;		/* do we have the Windows Caret? */
static RECT update;		/* current update rectangle (before scroll) */
static BOOL haveUpdate;		/* do we have an update rectangle? */
static BOOL bottomOnOutput;	/* do we scroll to bottom on output? */
static BOOL autoCopy = TRUE;	/* do we automatically copy selection
				 * to clipboard? */
static CursorStyle cursorStyle;	/* terminal cursor style */

static BOOL useIniGeometry = TRUE;	/* should we update .INI file */

static int vscrollWidth;		/* width of a vertical scrollbar */

/* .INI File Strings
 */
static char termStr[]		= "Terminal";
static char sizeStr[]		= "Size";
static char autoCopyStr[]	= "Auto Copy";
static char bottomOnOutputStr[] = "Bottom On Output";
static char cursorStyleStr[]	= "Cursor Style";
static char attachPrinterStr[]	= "Attached Printer";
static char printScreenStr[]	= "Enable PrintScreen";

/* static unsigned char* termCaretBits; -- not used ?! LZS*/
/* bits that make up the caret bitmap */

static COLORREF colors[] = {
    RGB(0,0,0),			/* Black */
    RGB(200,0,0),		/* Red */
    RGB(0,200,0),		/* Green */
    RGB(200,200,0),		/* Yellow */
    RGB(0,0,200),		/* Blue */
    RGB(200,0,200),		/* Magenta */
    RGB(0,200,200),		/* Cyan */
    RGB(200,200,200),		/* White */

    RGB(100,100,100),		/* Bold Black */
    RGB(255,0,0),		/* Bold Red */
    RGB(0,255,0),		/* Bold Green */
    RGB(255,255,0),		/* Bold Yellow */
    RGB(30,144,255),		/* Bold Blue */
    RGB(255,0,255),		/* Bold Magenta */
    RGB(0,255,255),		/* Bold Cyan */
    RGB(255,255,255)		/* Bold White */
};
#define PaletteSize numElem(colors)

static void termFuncKeyDown(BOOL shiftPressed, int nFkey);
static void selectCheckOverlap(int y1, int x1, int y2, int x2);

#ifdef WIN32
static UINT WM_TERM_WHEEL = 0;
#endif

/*********************
 * WINDOW MANAGEMENT *
 *********************/
/* Return the line array index of the line at the top of the terminal
 * (unscrolled window)
 */
int winTerminalTopLine()
{
    return term.numLinesUsed <= term.winSize.cy
	? 0 : term.numLinesUsed - term.winSize.cy;
}

/* Return a terminal line converted to a window line index, taking
 * account of scrolling backwards in history.
 *
 * Args:
 * ypos - cursor position to convert to window line index
 */
int winTerminalToWindow(int ypos)
{
    return ypos + winTerminalTopLine() - term.topVisibleLine;
}

/* Move the caret to the specifed character position
 *
 * Args:
 * x - the terminal column to move the caret to
 * y - the terminal line to move the caret to
 */
void winCaretPos(int x, int y)
{
    y = winTerminalToWindow(y);
    SetCaretPos(
	x * term.charSize.cx + term.cursorRect.left,
	y * term.charSize.cy + term.cursorRect.top
    );
}

/* Set the history scrollbar to indicate the visible part of the
 * line array
 */
void winSetScrollbar()
{
#ifdef WIN32
    int range = (term.numLinesUsed <= term.winSize.cy)
	? term.winSize.cy : term.numLinesUsed;
    SCROLLINFO scrollInfo;
    scrollInfo.cbSize = sizeof(scrollInfo);
		scrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
    scrollInfo.nMin = 0;
    scrollInfo.nMax = range - 1;
    scrollInfo.nPage = term.winSize.cy;
    scrollInfo.nPos = term.topVisibleLine;
    scrollInfo.nTrackPos = 0;
    SetScrollInfo(termWnd, SB_VERT, &scrollInfo, TRUE);
#else
    int range = (term.numLinesUsed <= term.winSize.cy)
	? 1 : term.numLinesUsed - term.winSize.cy;
    SetScrollRange(termWnd, SB_VERT, 0, range, TRUE);
    SetScrollPos(termWnd, SB_VERT, term.topVisibleLine, TRUE);
#endif
}

/* Force windows to update the part of the window we have changed
 */
void winUpdate()
{
    if (haveUpdate) {
	/* We have accumulated some changes to the terminal window in
	 * the update rect.  Convert the top and bottom from terminal
	 * to window ordinates so we can check if the updates are
	 * visible.
	 */
	update.top = winTerminalToWindow(update.top);
	update.bottom = winTerminalToWindow(update.bottom);

	/* Since the terminal is always at the end of the line array,
	 * it is not possible to scroll down past the terminal.  We
	 * can only scroll up.  We only have to check if the top
	 * updated line is still visible.
	 */
	if (update.top < term.winSize.cy) {
	    /* The update rect is visible, build a window rect that
	     * encloses the terminal update rect
	     */
	    RECT rect;

	    if (update.top < 0)
		update.top = 0;
	    if (update.bottom >= term.winSize.cy)
		update.bottom = term.winSize.cy - 1;
	    rect.top = update.top * term.charSize.cy;
	    rect.left = update.left * term.charSize.cx;
	    rect.bottom = (update.bottom + 1) * term.charSize.cy;
	    rect.right = (update.right + 1) * term.charSize.cx;
	    /* Invalidate the window rect
	     */
			InvalidateRect(termWnd, &rect, FALSE);
	}
	haveUpdate = FALSE;
    }
    /* Force windows to perform any pending updates
     */
    UpdateWindow(termWnd);
}

/* Scroll the region a number of lines.  Positive values scroll lines
 * up.
 *
 * Args:
 * numLines - the number of lines to scroll the scroll region.
 */
void winScrollRegion(int numLines)
{
    RECT rect;			/* build window rect to scroll */

    rect.left = 0;
    rect.right = term.winSize.cx * term.charSize.cx;

    if (numLines < 0) {
	/* Scroll lines down
	 */
	rect.top = winTerminalToWindow(term.scrollTop) * term.charSize.cy;
	rect.bottom = (winTerminalToWindow(term.scrollBottom) + numLines)
	    * term.charSize.cy;
    } else {
	/* Scroll lines up
	 */
	rect.top = (winTerminalToWindow(term.scrollTop) + numLines)
			* term.charSize.cy;
	rect.bottom = winTerminalToWindow(term.scrollBottom) * term.charSize.cy;
    }

    /* Force pending updates - be paranoid to prevent windows getting
     * confused about what needs to be updated.
     */
    winUpdate();
    /* Scroll the region
     */
    ScrollWindow(termWnd, 0, -numLines * term.charSize.cy, &rect, NULL);
}

/* Scroll the entire window a number of lines.  Positive values scroll
 * lines up.
 *
 * Args:
 * numLines - the number of lines to scroll
 */
void winScrollWindow(int numLines)
{
    ScrollWindow(termWnd, 0, -numLines * term.charSize.cy, NULL, NULL);
}

/* The oldest line in the history buffer has been removed
 */
void winTopLineRemoved()
{
    if (term.topVisibleLine == 0)
	winScrollWindow(1);
    else
	term.topVisibleLine--;

    if (term.haveSelection) {
	/* We have a selection, make sure we adjust the selection
	 * range to account for the top line being removed.
	 */
	term.selectFrom.y--;
	if (term.selectFrom.y < 0) {
	    term.selectFrom.y = 0;
	    term.selectFrom.x = 0;
	}
	term.selectTo.y--;
	if (term.selectTo.y < 0)
	    term.haveSelection = FALSE;
    }
}

/* Add an area to the terminal window update rect
 *
 * Args:
 * y1 - top terminal line modified
 * x1 - left column modified
 * y2 - bottom terminal line modified
 * x2 - right column modified
 */
void winModifyRange(int y1, int x1, int y2, int x2)
{
    /* Hide the selection if it overlaps with the modified area.
     */
    selectCheckOverlap(linesTerminalToLine(y1), x1,
		       linesTerminalToLine(y2), x2);

    if (!haveUpdate) {
	/* No previous update rect.  The modified area is the update
	 * rect
	 */
	update.top = y1;
	update.left = x1;
	update.bottom = y2;
	update.right = x2;
	haveUpdate = TRUE;
	return;
    }

    /* Merge the modified area with the update rect
     */
    if (y1 < update.top)
	update.top = y1;
    if (x1 < update.left)
	update.left = x1;
    if (y2 > update.bottom)
	update.bottom = y2;
    if (x2 > update.right)
	update.right = x2;
}

/* A number of lines were inserted into the terminal.
 *
 * Args:
 * posy     - terminal line to insert lines at
 * bottom   - bottom line affected by scrolling
 * numLines - number of lines to insert
 */
void winLinesInsert(int posy, int bottom, int numLines)
{
    RECT rect;			/* build window rect to scroll */
    RECT client;		/* query client window size */

    if (posy >= bottom)
	/* No lines to scroll
	 */
	return;

    /* Hide the selection if it overlaps the inserted lines
     */
    selectCheckOverlap(linesTerminalToLine(posy), 0,
		       linesTerminalToLine(bottom), term.winSize.cx);

    /* Convert terminal line position to window line.
     */
		posy = winTerminalToWindow(posy);
    if (posy >= term.winSize.cy)
	/* Cannot see the insertion point - nothing to do
	 */
	return;
    bottom = winTerminalToWindow(bottom);

    /* Do not bother scrolling a part of the window we will not see
     */
    if (posy + numLines > bottom)
	numLines = bottom - posy;

    /* Build scroll rect
     */
    GetClientRect(termWnd, &client);
    rect.left = 0;
    rect.top = posy * term.charSize.cy;
    rect.right = client.right;
    rect.bottom = (bottom - numLines) * term.charSize.cy;

    /* Force an update before we scroll - windows bug avoidance
     */
    winUpdate();
    ScrollWindow(termWnd, 0, term.charSize.cy * numLines, &rect, NULL);
    /* Invalidate the part of the window exposed
     */
    rect.left = 0;
    rect.top = posy * term.charSize.cy;
    rect.right = client.right;
    rect.bottom = numLines * term.charSize.cy;
    InvalidateRect(termWnd, &rect, FALSE);
}

/* Some characters were inserted into a line.
 *
 * Args:
 * posy -     line that characters were inserted into
 * posx -     column at which characters were inserted
 */
void winCharsInsert(int posy, int posx)
{
    int posyIdx = linesTerminalToLine(posy);

    /* Hide the selection if it overlaps the inserted characters
     */
    selectCheckOverlap(posyIdx, posx, posyIdx, term.winSize.cx);

    /* Add the affected line, from the insert column to the end to the
     * update rect.
     */
    winModifyRange(posy, posx, posy, term.winSize.cx);
}

/* A number of lines were deleted from the terminal
 *
 * Args:
 * posy     - terminal line to insert lines at
 * bottom   - bottom line affected by scrolling
 * numLines - number of lines to delete
 */
void winLinesDelete(int posy, int bottom, int numLines)
{
    RECT rect;			/* build window rect to scroll */
		RECT client;		/* query client window size */

    if (posy >= bottom)
	/* No lines to scroll
	 */
	return;

    /* Hide the selection if it overlaps the inserted lines
     */
    selectCheckOverlap(linesTerminalToLine(posy), 0,
		       linesTerminalToLine(bottom), term.winSize.cx);

    /* Convert the terminal line position to window line.
     */
    posy = winTerminalToWindow(posy);
    if (posy >= term.winSize.cy)
	/* We cannot see the affected portion of the screen - nothing
	 * to do
	 */
	return;
    bottom = winTerminalToWindow(bottom);

    /* Do not scroll lines we cannot see
     */
    if (posy + numLines > bottom)
	numLines = bottom - posy;

    /* Build scroll rect
     */
    GetClientRect(termWnd, &client);
    rect.left = 0;
    rect.top = (posy + numLines) * term.charSize.cy;
		rect.right = client.right;
    rect.bottom = bottom * term.charSize.cy;

    /* Force an update before we scroll - windows bug avoidance
     */
    winUpdate();
    ScrollWindow(termWnd, 0, -term.charSize.cy * numLines, &rect, NULL);
    /* Invalidate the part of the window exposed
     */
    rect.left = 0;
    rect.top = (bottom - numLines) * term.charSize.cy;
    rect.right = client.right;
    rect.bottom = bottom * term.charSize.cy;
    InvalidateRect(termWnd, &rect, FALSE);
}

/* Some characters were deleted from a line
 *
 * Args:
 * posy -     line that characters were deleted from
 * posx -     column at which characters were deleted
 */
void winCharsDelete(int posy, int posx)
{
    int posyIdx = linesTerminalToLine(posy);

    /* Hide the selection if it overlaps the inserted characters
     */
    selectCheckOverlap(posyIdx, posx, posyIdx, term.winSize.cx);

    /* Add the affected line, from the delete column to the end to the
		 * update rect.
     */
    winModifyRange(posy, posx, posy, term.winSize.cx);
}

/************************
 * SELECTION MANAGEMENT *
 ************************/

/* Return the start and end of the selection (start < end)
 *
 * Args:
 * start - returns the start of the selection
 * end -   returns the end of the selection
 *
 * The POINT.y ordinate is a line array index
 */
static void termSelectGetRange(POINT* start, POINT* end)
{
    if (term.selectFrom.y > term.selectTo.y
	|| term.selectFrom.y == term.selectTo.y
	&& term.selectFrom.x > term.selectTo.x) {
	*start = term.selectTo;
	*end = term.selectFrom;
    } else {
	*start = term.selectFrom;
	*end = term.selectTo;
    }
}

/* Invalidate the area of the window that contains the selection
 *
 * Args:
 * y1 - line index of selection start
 * x1 - column number of selection start
 * y2 - line index of selection end
 * x2 - column number of selection end

 * LZS: x1 and x2 are indifferent
 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -