📄 dtelnet.c
字号:
/* dtelnet.c
* Copyright (c) 1997 David Cole
*
* Mainline for the dtelnet program. The actions performed are:
* - All menu management.
* - .INI and .HLP file identification.
* - Application window management.
* - Child window placement.
* - Command line argument parsing.
*
* The application window has two child windows; the terminal window,
* and the status bar. No drawing is performed in the application
* window.
*/
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <direct.h>
#include "platform.h"
#include "utils.h"
#include "log.h"
#include "term.h"
#include "emul.h"
#include "socket.h"
#include "about.h"
#include "connect.h"
#include "filetype.h"
#include "status.h"
#include "font.h"
#include "argv.h"
#include "dialog.h"
#include "raw.h"
#include "termdef.h"
#include "printing.h"
#include "editor.h"
#include "proxy.h"
#include "dtchars.h"
#include "dtelnet.h"
/* Windows classname of application window
*/
static char* telnetWinClass = "DTelnetWClass";
static HWND telnetWnd; /* handle of application window */
static HINSTANCE instanceHnd; /* application instance handle */
static char helpFileName[_MAX_PATH + 1]; /* Help file name*/
static char iniFileName[_MAX_PATH + 1]; /* INI file to use */
EmulNames emuls;
HINSTANCE telnetGetInstance(void)
{
return instanceHnd;
}
HWND telnetGetWnd(void)
{
return telnetWnd;
}
/* Destroy the application window to trigger exit
*/
void telnetExit()
{
DestroyWindow(telnetWnd);
}
/* Return the name of the application
*/
char* telnetAppName()
{
return "Dave's Telnet";
}
/* Report a fatal error then exit
*
* Args:
* fmt - printf format string
* ... - arguments to format string
*/
void telnetFatal(const char* fmt, ...)
{
va_list ap;
char msg[512];
va_start(ap, fmt);
vsprintf(msg, fmt, ap);
MessageBox(telnetWnd, msg, telnetAppName(),
MB_APPLMODAL|MB_ICONSTOP|MB_OK);
telnetExit();
}
/* Return the name of the .INI file
*/
char* telnetIniFile()
{
return iniFileName;
}
/* Add previous connections to the history on the menu.
*
* Args:
* menu - handle of application window menu
*
* Maintain the connection history in the Connect menu. Gray entries
* when we are online.
*/
static void addConnectHistory(HMENU menu)
{
int num; /* iterate over connection history */
char histline [MAX_HISTORY_SIZE];
char* text; /* formatted session */
UINT action = socketOffline() ? MF_ENABLED : MF_GRAYED;
for (num = 0; (text = connectGetHistory (histline, num, TRUE)) != NULL; ++num) {
int id = ID_CONNECT_HISTORY + num;
if (GetMenuState(menu, id, MF_BYCOMMAND) == (UINT)-1) {
if (num == 0)
AppendMenu(menu, MF_ENABLED | MF_SEPARATOR, 0, NULL);
AppendMenu(menu, action, id, text);
} else
ModifyMenu(menu, id, MF_BYCOMMAND | action, id, text);
}
}
/* Menu is about to pop up - customise it
*
* Args:
* wnd - handle of application window
* menu - handle of application window menu
*/
static void initMenu(HWND wnd, HMENU menu)
{
const char *termname;
HMENU terminalMenu, emulateMenu;
unsigned int i;
if (socketOffline()) {
/* We are offline, enable connect, disable disconnect
*/
EnableMenuItem(menu, (UINT)ID_CONNECT_REMOTE_SYSTEM,
MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(menu, (UINT)ID_CONNECT_DISCONNECT,
MF_BYCOMMAND | MF_GRAYED);
/* Disable copy/paste
*/
EnableMenuItem(menu, ID_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(menu, ID_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
/* Enable Proxy Settings
*/
EnableMenuItem(menu, (UINT)ID_CONNECT_PROXY, MF_BYCOMMAND | MF_ENABLED);
} else {
/* We are online, disable connect, enable disconnect
*/
EnableMenuItem(menu, (UINT)ID_CONNECT_REMOTE_SYSTEM,
MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(menu, (UINT)ID_CONNECT_DISCONNECT,
MF_BYCOMMAND | MF_ENABLED);
/* Enable copy if we are in windows select mode, and there is
* a selection.
*/
EnableMenuItem(menu, ID_EDIT_COPY,
MF_BYCOMMAND | (!termAutoCopy() && termHaveSelection()
? MF_ENABLED : MF_GRAYED));
/* Enable Edit/Paste when there is text on clipboard
*/
if (OpenClipboard(wnd)) {
if (IsClipboardFormatAvailable(CF_TEXT)
|| IsClipboardFormatAvailable(CF_OEMTEXT))
EnableMenuItem(menu, ID_EDIT_PASTE, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(menu, ID_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
CloseClipboard();
}
/* Disable Proxy Settings
*/
EnableMenuItem(menu, (UINT)ID_CONNECT_PROXY, MF_BYCOMMAND | MF_GRAYED);
}
/* Initialise the Connect menu
*/
CheckMenuItem(menu, (UINT)ID_CONNECT_EXIT_DISCONNECT,
MF_BYCOMMAND | (connectGetExitOnDisconnect()
? MF_CHECKED : MF_UNCHECKED));
addConnectHistory(GetSubMenu(menu, 0));
/* Initialise the Edit menu
*/
CheckMenuItem(menu, (UINT)ID_EDIT_AUTO_COPY,
MF_BYCOMMAND | (termAutoCopy()
? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, (UINT)ID_TERMINAL_BOTTOM_ON_OUTPUT,
MF_BYCOMMAND | (termBottomOnOutput()
? MF_CHECKED : MF_UNCHECKED));
if (editGetCMMode()==ID_CM_FREE) {
CheckMenuItem(menu, ID_CM_FREE, MF_BYCOMMAND | MF_CHECKED);
CheckMenuItem(menu, ID_CM_TEXT, MF_BYCOMMAND | MF_UNCHECKED);
} else {
CheckMenuItem(menu, ID_CM_FREE, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(menu, ID_CM_TEXT, MF_BYCOMMAND | MF_CHECKED);
}
CheckMenuItem(menu, (UINT)ID_TERMINAL_BACKSPACE_ALT,
MF_BYCOMMAND | (connectGetBs2DelOption() ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, ID_TERMINAL_CS_BLOCK,
MF_BYCOMMAND | (termCursorStyle() == cursorBlock) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(menu, ID_TERMINAL_CS_UNDERLINE,
MF_BYCOMMAND | (termCursorStyle() == cursorUnderLine) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(menu, ID_TERMINAL_CS_VERTLINE,
MF_BYCOMMAND | (termCursorStyle() == cursorVertLine) ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem(menu, (UINT)ID_TERMINAL_START_LOGGING,
MF_BYCOMMAND | (logLogging() ? MF_GRAYED : MF_ENABLED));
EnableMenuItem(menu, (UINT)ID_TERMINAL_STOP_LOGGING,
MF_BYCOMMAND | (logLogging() ? MF_ENABLED : MF_GRAYED));
CheckMenuItem(menu, (UINT)ID_TERMINAL_LOG_SESSION,
MF_BYCOMMAND | (logLoggingSession()
? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, (UINT)ID_TERMINAL_LOG_PROTOCOL,
MF_BYCOMMAND | (logLoggingProtocol()
? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, (UINT)ID_TERMINAL_ATTPRINT,
MF_BYCOMMAND | (termAttachedPrinter()
? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, (UINT)ID_TERMINAL_ENABLE_PRINTSCR,
MF_BYCOMMAND | (termPrintScreenEnabled()
? MF_CHECKED : MF_UNCHECKED));
EnableMenuItem(menu, (UINT)ID_TERMINAL_PRINTSCREEN,
MF_BYCOMMAND | (termPrintScreenEnabled() ? MF_ENABLED : MF_GRAYED));
/* Initialise the Terminal menu
*/
telnetEnumTermProfiles(&emuls);
termname = emulGetTerm()->name;
terminalMenu = GetSubMenu(menu, 3);
if (!terminalMenu) return;
emulateMenu = GetSubMenu(terminalMenu, 4);
if (!emulateMenu) return;
for (i=0; i < emuls.num; i++)
{
int id = ID_MENU_EMULATE_FIRST + i;
if (GetMenuState(menu, id, MF_BYCOMMAND) == (UINT)-1) {
AppendMenu(emulateMenu, MF_STRING, id, emuls.names[i]);
} else
ModifyMenu(menu, id, MF_BYCOMMAND | MF_STRING, id, emuls.names[i]);
CheckMenuItem(emulateMenu, id, MF_BYCOMMAND
| (strcmp(termname, emuls.names[i])==0 ? MF_CHECKED : MF_UNCHECKED));
}
}
/* The telnet window has been created, the terminal window has been
* created and sized. Set our initial window size if given.
*/
void initSetWindowPos(HWND telnetWnd)
{
RECT workspace; /* the area of the useable workspace */
RECT window; /* the area of the application window */
int x, y; /* the new coordinates of the window */
if (!term.useInitPos)
return;
#ifdef WIN32
SystemParametersInfo(SPI_GETWORKAREA, 0, &workspace, 0);
#else
workspace.left = workspace.top = 0;
workspace.right = GetSystemMetrics(SM_CXSCREEN);
workspace.bottom = GetSystemMetrics(SM_CYSCREEN);
#endif
GetWindowRect(telnetWnd, &window);
if (term.winInitPos.cx < 0)
x = workspace.right - (window.right - window.left)
+ term.winInitPos.cx;
else
x = term.winInitPos.cx;
if (term.winInitPos.cy < 0)
y = workspace.bottom - (window.bottom - window.top)
+ term.winInitPos.cy;
else
y = term.winInitPos.cy;
SetWindowPos(telnetWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
static void recalcInitPos(void)
{
RECT rect;
RECT workspace; /* the area of the useable workspace */
if (!term.useInitPos)
return;
GetWindowRect(telnetWnd, &rect);
#ifdef WIN32
SystemParametersInfo(SPI_GETWORKAREA, 0, &workspace, 0);
#else
workspace.top = workspace.left = 0;
workspace.right = GetSystemMetrics(SM_CXSCREEN);
workspace.bottom = GetSystemMetrics(SM_CYSCREEN);
#endif
if (rect.left >= 0)
term.winInitPos.cx = rect.left;
else
term.winInitPos.cx = rect.right - workspace.right;
if (rect.top >= 0)
term.winInitPos.cy = rect.top;
else
term.winInitPos.cy = rect.bottom - workspace.bottom;
statusRedraw();
}
/* The terminal window has just resized to specified width/height. We
* have to resize ourselves to allow the terminal resize.
*
* Args:
* xs - width (in pixels) of the terminal child window
* ys - height (in pixels) of the terminal child window
*/
void telnetTerminalSize(int xs, int ys)
{
RECT window; /* screen rectangle of application window */
RECT client; /* size of client rectangle */
RECT status; /* size/position of status bar */
SIZE newSize; /* calculate new size of application window */
int statusHeight; /* calculate height of status bar child */
/* Query and calculate current sizes and positions of all players
*/
GetWindowRect(telnetWnd, &window);
GetClientRect(telnetWnd, &client);
GetWindowRect(statusGetWnd(), &status);
statusHeight = status.bottom - status.top;
/* Work out the new size of the application window
*/
newSize.cx = xs + window.right - window.left - client.right;
newSize.cy = ys + window.bottom - window.top - client.bottom
+ statusHeight;
/* Now make ourselves the adjusted size
*/
SetWindowPos(telnetWnd, HWND_TOPMOST, 0, 0,
newSize.cx, newSize.cy,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
/* Move the status bar to the new position
*/
MoveWindow(statusGetWnd(), 0, ys, xs, statusHeight, TRUE);
}
/* The user is dragging the window frame. Modify the resize as it is
* happening to force a grid of one character.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -