📄 window.c
字号:
#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <time.h>#include <assert.h>#define PUTTY_DO_GLOBALS /* actually _define_ globals */#include "putty.h"#include "terminal.h"#include "storage.h"#include "win_res.h"#ifndef NO_MULTIMON#if WINVER < 0x0500#define COMPILE_MULTIMON_STUBS#include <multimon.h>#endif#endif#include <imm.h>#include <commctrl.h>#include <richedit.h>#include <mmsystem.h>#define IDM_SHOWLOG 0x0010#define IDM_NEWSESS 0x0020#define IDM_DUPSESS 0x0030#define IDM_RESTART 0x0040#define IDM_RECONF 0x0050#define IDM_CLRSB 0x0060#define IDM_RESET 0x0070#define IDM_HELP 0x0140#define IDM_ABOUT 0x0150#define IDM_SAVEDSESS 0x0160#define IDM_COPYALL 0x0170#define IDM_FULLSCREEN 0x0180#define IDM_PASTE 0x0190#define IDM_SESSLGP 0x0250 /* log type printable */#define IDM_SESSLGA 0x0260 /* log type all chars */#define IDM_SESSLGE 0x0270 /* log end */#define IDM_SPECIAL_MIN 0x0400#define IDM_SPECIAL_MAX 0x0800#define IDM_SAVED_MIN 0x1000#define IDM_SAVED_MAX 0x2000#define WM_IGNORE_CLIP (WM_XUSER + 2)#define WM_FULLSCR_ON_MAX (WM_XUSER + 3)#define WM_AGENT_CALLBACK (WM_XUSER + 4)/* Needed for Chinese support and apparently not always defined. */#ifndef VK_PROCESSKEY#define VK_PROCESSKEY 0xE5#endif/* Mouse wheel support. */#ifndef WM_MOUSEWHEEL#define WM_MOUSEWHEEL 0x020A /* not defined in earlier SDKs */#endif#ifndef WHEEL_DELTA#define WHEEL_DELTA 120#endifstatic Mouse_Button translate_button(Mouse_Button button);static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output);static void cfgtopalette(void);static void systopalette(void);static void init_palette(void);static void init_fonts(int, int);static void another_font(int);static void deinit_fonts(void);static void set_input_locale(HKL);static int is_full_screen(void);static void make_full_screen(void);static void clear_full_screen(void);static void flip_full_screen(void);/* Window layout information */static void reset_window(int);static int extra_width, extra_height;static int font_width, font_height, font_dualwidth;static int offset_width, offset_height;static int was_zoomed = 0;static int prev_rows, prev_cols; static int pending_netevent = 0;static WPARAM pend_netevent_wParam = 0;static LPARAM pend_netevent_lParam = 0;static void enact_pending_netevent(void);static void flash_window(int mode);static void sys_cursor_update(void);static int is_shift_pressed(void);static int get_fullscreen_rect(RECT * ss);static time_t last_movement = 0;static int caret_x = -1, caret_y = -1;static int kbd_codepage;static void *ldisc;static const Backend *back;static void *backhandle;static struct unicode_data ucsdata;static int session_closed;static const struct telnet_special *specials;static int n_specials;static struct { HMENU menu; int specials_submenu_pos;} popup_menus[2];enum { SYSMENU, CTXMENU };Config cfg; /* exported to windlg.c */extern struct sesslist sesslist; /* imported from windlg.c */struct agent_callback { void (*callback)(void *, void *, int); void *callback_ctx; void *data; int len;};#define FONT_NORMAL 0#define FONT_BOLD 1#define FONT_UNDERLINE 2#define FONT_BOLDUND 3#define FONT_WIDE 0x04#define FONT_HIGH 0x08#define FONT_NARROW 0x10#define FONT_OEM 0x20#define FONT_OEMBOLD 0x21#define FONT_OEMUND 0x22#define FONT_OEMBOLDUND 0x23#define FONT_MAXNO 0x2F#define FONT_SHIFT 5static HFONT fonts[FONT_MAXNO];static LOGFONT lfont;static int fontflag[FONT_MAXNO];static enum { BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT} bold_mode;static enum { UND_LINE, UND_FONT} und_mode;static int descent;#define NCOLOURS 24static COLORREF colours[NCOLOURS];static HPALETTE pal;static LPLOGPALETTE logpal;static RGBTRIPLE defpal[NCOLOURS];static HWND hwnd;static HBITMAP caretbm;static int dbltime, lasttime, lastact;static Mouse_Button lastbtn;/* this allows xterm-style mouse handling. */static int send_raw_mouse = 0;static int wheel_accumulator = 0;static char *window_name, *icon_name;static int compose_state = 0;static UINT wm_mousewheel = WM_MOUSEWHEEL;/* Dummy routine, only required in plink. */void ldisc_update(void *frontend, int echo, int edit){}static void start_backend(void){ const char *error; char msg[1024], *title; char *realhost; int i; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ back = NULL; for (i = 0; backends[i].backend != NULL; i++) if (backends[i].protocol == cfg.protocol) { back = backends[i].backend; break; } if (back == NULL) { char *str = dupprintf("%s Internal Error", appname); MessageBox(NULL, "Unsupported protocol number found", str, MB_OK | MB_ICONEXCLAMATION); sfree(str); cleanup_exit(1); } error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, cfg.tcp_keepalives); back->provide_logctx(backhandle, logctx); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" "%.800s\n" "%s", cfg.host, error); MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); sfree(str); exit(0); } window_name = icon_name = NULL; if (*cfg.wintitle) { title = cfg.wintitle; } else { sprintf(msg, "%s - %s", realhost, appname); title = msg; } sfree(realhost); set_title(NULL, title); set_icon(NULL, title); /* * Connect the terminal to the backend for resize purposes. */ term_provide_resize_fn(term, back->size, backhandle); /* * Set up a line discipline. */ ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); /* * Destroy the Restart Session menu item. (This will return * failure if it's already absent, as it will be the very first * time we call this function. We ignore that, because as long * as the menu item ends up not being there, we don't care * whether it was us who removed it or not!) */ for (i = 0; i < lenof(popup_menus); i++) { DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); } session_closed = FALSE;}static void close_session(void){ char morestuff[100]; int i; session_closed = TRUE; sprintf(morestuff, "%.70s (inactive)", appname); set_icon(NULL, morestuff); set_title(NULL, morestuff); if (ldisc) { ldisc_free(ldisc); ldisc = NULL; } if (back) { back->free(backhandle); backhandle = NULL; back = NULL; update_specials_menu(NULL); } /* * Show the Restart Session menu item. Do a precautionary * delete first to ensure we never end up with more than one. */ for (i = 0; i < lenof(popup_menus); i++) { DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, IDM_RESTART, "&Restart Session"); }}int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show){ WNDCLASS wndclass; MSG msg; int guess_width, guess_height; hinst = inst; statics()->flags = FLAG_VERBOSE | FLAG_INTERACTIVE; sk_init(); InitCommonControls(); /* Ensure a Maximize setting in Explorer doesn't maximise the * config box. */ defuse_showwindow(); if (!init_winver()) { char *str = dupprintf("%s Fatal Error", appname); MessageBox(NULL, "Windows refuses to report a version", str, MB_OK | MB_ICONEXCLAMATION); sfree(str); return 1; } /* * If we're running a version of Windows that doesn't support * WM_MOUSEWHEEL, find out what message number we should be * using instead. */ if (osVersion.dwMajorVersion < 4 || (osVersion.dwMajorVersion == 4 && osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT)) wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG"); /* * See if we can find our Help file. */ { char b[2048], *p, *q, *r; FILE *fp; GetModuleFileName(NULL, b, sizeof(b) - 1); r = b; p = strrchr(b, '\\'); if (p && p >= r) r = p+1; q = strrchr(b, ':'); if (q && q >= r) r = q+1; strcpy(r, "putty.hlp"); if ( (fp = fopen(b, "r")) != NULL) { help_path = dupstr(b); fclose(fp); } else help_path = NULL; strcpy(r, "putty.cnt"); if ( (fp = fopen(b, "r")) != NULL) { help_has_contents = TRUE; fclose(fp); } else help_has_contents = FALSE; } /* * Process the command line. */ { char *p; int got_host = 0; statics()->default_protocol = be_default_protocol; /* Find the appropriate default port. */ { int i; statics()->default_port = 0; /* illegal */ for (i = 0; backends[i].backend != NULL; i++) if (backends[i].protocol == statics()->default_protocol) { statics()->default_port = backends[i].backend->default_port; break; } } cfg.logtype = LGTYP_NONE; do_defaults(NULL, &cfg); p = cmdline; /* * Process a couple of command-line options which are more * easily dealt with before the line is broken up into * words. These are the soon-to-be-defunct @sessionname and * the internal-use-only &sharedmemoryhandle, neither of * which are combined with anything else. */ while (*p && isspace(*p)) p++; if (*p == '@') { int i = strlen(p); while (i > 1 && isspace(p[i - 1])) i--; p[i] = '\0'; do_defaults(p + 1, &cfg); if (!*cfg.host && !do_config()) { cleanup_exit(0); } } else if (*p == '&') { /* * An initial & means we've been given a command line * containing the hex value of a HANDLE for a file * mapping object, which we must then extract as a * config. */ HANDLE filemap; Config *cp; if (sscanf(p + 1, "%p", &filemap) == 1 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, 0, 0, sizeof(Config))) != NULL) { cfg = *cp; UnmapViewOfFile(cp); CloseHandle(filemap); } else if (!do_config()) { cleanup_exit(0); } } else { /* * Otherwise, break up the command line and deal with * it sensibly. */ int argc, i; char **argv; split_into_argv(cmdline, &argc, &argv, NULL); for (i = 0; i < argc; i++) { char *p = argv[i]; int ret; ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL, 1, &cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", p); } else if (ret == 2) { i++; /* skip next argument */ } else if (ret == 1) { continue; /* nothing further needs doing */ } else if (!strcmp(p, "-cleanup")) { /* * `putty -cleanup'. Remove all registry * entries associated with PuTTY, and also find * and delete the random seed file. */ char *s1, *s2; s1 = dupprintf("This procedure will remove ALL Registry\n" "entries associated with %s, and will\n" "also remove the random seed file.\n" "\n" "THIS PROCESS WILL DESTROY YOUR SAVED\n" "SESSIONS. Are you really sure you want\n" "to continue?", appname); s2 = dupprintf("%s Warning", appname); if (MessageBox(NULL, s1, s2, MB_YESNO | MB_ICONWARNING) == IDYES) { cleanup_all(); } sfree(s1); sfree(s2); exit(0); } else if (*p != '-') { char *q = p; if (got_host) { /* * If we already have a host name, treat * this argument as a port number. NB we * have to treat this as a saved -P * argument, so that it will be deferred * until it's a good moment to run it. */ int ret = cmdline_process_param("-P", p, 1, &cfg); assert(ret == 2); } else if (!strncmp(q, "telnet:", 7)) { /* * If the hostname starts with "telnet:", * set the protocol to Telnet and process * the string as a Telnet URL. */ char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg.protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg.port = atoi(p); else cfg.port = -1; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; got_host = 1; } else { /* * Otherwise, treat this argument as a host
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -