X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/fdedf2c8af53ae30fc508b55dc9754405ae3c9af..cabfd08c97213abe46f996a93407f8209fc38b94:/window.c diff --git a/window.c b/window.c index 3cd719ae..fd46be4c 100644 --- a/window.c +++ b/window.c @@ -3,31 +3,36 @@ #include #include #include +#include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" #include "win_res.h" -#define IDM_SHOWLOG 501 -#define IDM_NEWSESS 502 -#define IDM_DUPSESS 503 -#define IDM_RECONF 504 -#define IDM_CLRSB 505 -#define IDM_RESET 506 -#define IDM_TEL_AYT 507 -#define IDM_TEL_BRK 508 -#define IDM_TEL_SYNCH 509 -#define IDM_TEL_EC 510 -#define IDM_TEL_EL 511 -#define IDM_TEL_GA 512 -#define IDM_TEL_NOP 513 -#define IDM_TEL_ABORT 514 -#define IDM_TEL_AO 515 -#define IDM_TEL_IP 516 -#define IDM_TEL_SUSP 517 -#define IDM_TEL_EOR 518 -#define IDM_TEL_EOF 519 -#define IDM_ABOUT 520 +#define IDM_SHOWLOG 0x0010 +#define IDM_NEWSESS 0x0020 +#define IDM_DUPSESS 0x0030 +#define IDM_RECONF 0x0040 +#define IDM_CLRSB 0x0050 +#define IDM_RESET 0x0060 +#define IDM_TEL_AYT 0x0070 +#define IDM_TEL_BRK 0x0080 +#define IDM_TEL_SYNCH 0x0090 +#define IDM_TEL_EC 0x00a0 +#define IDM_TEL_EL 0x00b0 +#define IDM_TEL_GA 0x00c0 +#define IDM_TEL_NOP 0x00d0 +#define IDM_TEL_ABORT 0x00e0 +#define IDM_TEL_AO 0x00f0 +#define IDM_TEL_IP 0x0100 +#define IDM_TEL_SUSP 0x0110 +#define IDM_TEL_EOR 0x0120 +#define IDM_TEL_EOF 0x0130 +#define IDM_ABOUT 0x0140 +#define IDM_SAVEDSESS 0x0150 + +#define IDM_SAVED_MIN 0x1000 +#define IDM_SAVED_MAX 0x2000 #define WM_IGNORE_SIZE (WM_USER + 2) #define WM_IGNORE_CLIP (WM_USER + 3) @@ -78,6 +83,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { MSG msg; int guess_width, guess_height; + putty_inst = inst; + winsock_ver = MAKEWORD(1, 1); if (WSAStartup(winsock_ver, &wsadata)) { MessageBox(NULL, "Unable to initialise WinSock", "WinSock Error", @@ -100,12 +107,33 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { { char *p; + default_protocol = DEFAULT_PROTOCOL; + default_port = DEFAULT_PORT; + do_defaults(NULL); p = cmdline; while (*p && isspace(*p)) p++; /* + * Process command line options first. Yes, this can be + * done better, and it will be as soon as I have the + * energy... + */ + while (*p == '-') { + char *q = p + strcspn(p, " \t"); + p++; + if (q == p + 3 && + tolower(p[0]) == 's' && + tolower(p[1]) == 's' && + tolower(p[2]) == 'h') { + default_protocol = cfg.protocol = PROT_SSH; + default_port = cfg.port = 22; + } + p = q + strspn(q, " \t"); + } + + /* * An initial @ means to activate a saved session. */ if (*p == '@') { @@ -123,7 +151,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { */ HANDLE filemap; Config *cp; - if (sscanf(p+1, "%x", &filemap) == 1 && + if (sscanf(p+1, "%p", &filemap) == 1 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, 0, 0, sizeof(Config))) != NULL) { cfg = *cp; @@ -153,7 +181,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } } - back = (cfg.protocol == PROT_SSH ? &ssh_backend : &telnet_backend); + back = (cfg.protocol == PROT_SSH ? &ssh_backend : + cfg.protocol == PROT_TELNET ? &telnet_backend : + &raw_backend); + + ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); if (!prev) { wndclass.style = 0; @@ -163,7 +195,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { wndclass.hInstance = inst; wndclass.hIcon = LoadIcon (inst, MAKEINTRESOURCE(IDI_MAINICON)); - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hCursor = LoadCursor (NULL, IDC_IBEAM); wndclass.hbrBackground = GetStockObject (BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = appname; @@ -267,7 +299,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { return 0; } window_name = icon_name = NULL; - sprintf(msg, "PuTTY: %s", realhost); + sprintf(msg, "%s - PuTTY", realhost); set_title (msg); set_icon (msg); } @@ -278,6 +310,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { inbuf_reap = inbuf_head = 0; outbuf_reap = outbuf_head = 0; + /* + * Choose unscroll method + */ + unscroll_event = US_DISP; + /* * Prepare the mouse handler. */ @@ -290,7 +327,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { */ { HMENU m = GetSystemMenu (hwnd, FALSE); - HMENU p; + HMENU p,s; + int i; AppendMenu (m, MF_SEPARATOR, 0, 0); if (cfg.protocol == PROT_TELNET) { @@ -312,11 +350,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { AppendMenu (p, MF_ENABLED, IDM_TEL_EOR, "End Of Record"); AppendMenu (p, MF_ENABLED, IDM_TEL_EOF, "End Of File"); AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) p, "Telnet Command"); - AppendMenu (m, MF_ENABLED, IDM_SHOWLOG, "Show Negotiation"); AppendMenu (m, MF_SEPARATOR, 0, 0); } + AppendMenu (m, MF_ENABLED, IDM_SHOWLOG, "Event Log"); + AppendMenu (m, MF_SEPARATOR, 0, 0); AppendMenu (m, MF_ENABLED, IDM_NEWSESS, "New Session"); AppendMenu (m, MF_ENABLED, IDM_DUPSESS, "Duplicate Session"); + s = CreateMenu(); + get_sesslist(TRUE); + for (i = 1 ; i < ((nsessions < 256) ? nsessions : 256) ; i++) + AppendMenu (s, MF_ENABLED, IDM_SAVED_MIN + (16 * i) , sessions[i]); + AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) s, "Saved Sessions"); AppendMenu (m, MF_ENABLED, IDM_RECONF, "Change Settings"); AppendMenu (m, MF_SEPARATOR, 0, 0); AppendMenu (m, MF_ENABLED, IDM_CLRSB, "Clear Scrollback"); @@ -472,8 +516,8 @@ static void init_fonts(void) { CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \ FIXED_PITCH | FF_DONTCARE, cfg.font) if (cfg.vtmode != VT_OEMONLY) { - f(FONT_NORMAL, ANSI_CHARSET, fw_dontcare, FALSE); - f(FONT_UNDERLINE, ANSI_CHARSET, fw_dontcare, TRUE); + f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE); + f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE); } if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_OEMONLY) { f(FONT_OEM, OEM_CHARSET, fw_dontcare, FALSE); @@ -481,8 +525,8 @@ static void init_fonts(void) { } if (bold_mode == BOLD_FONT) { if (cfg.vtmode != VT_OEMONLY) { - f(FONT_BOLD, ANSI_CHARSET, fw_bold, FALSE); - f(FONT_BOLDUND, ANSI_CHARSET, fw_bold, TRUE); + f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE); + f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE); } if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_OEMONLY) { f(FONT_OEMBOLD, OEM_CHARSET, fw_bold, FALSE); @@ -581,19 +625,28 @@ static int WINAPI WndProc (HWND hwnd, UINT message, switch (message) { case WM_CREATE: break; + case WM_CLOSE: + if (!cfg.warn_on_close || + MessageBox(hwnd, "Are you sure you want to close this session?", + "PuTTY Exit Confirmation", + MB_ICONWARNING | MB_OKCANCEL) == IDOK) + DestroyWindow(hwnd); + return 0; case WM_DESTROY: PostQuitMessage (0); return 0; case WM_SYSCOMMAND: - switch (wParam) { + switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */ case IDM_SHOWLOG: - shownegot(hwnd); + showeventlog(hwnd); break; case IDM_NEWSESS: case IDM_DUPSESS: + case IDM_SAVEDSESS: { char b[2048]; char c[30], *cl; + int freecl = FALSE; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE filemap = NULL; @@ -624,8 +677,17 @@ static int WINAPI WndProc (HWND hwnd, UINT message, UnmapViewOfFile(p); } } - sprintf(c, "putty &%08x", filemap); + sprintf(c, "putty &%p", filemap); cl = c; + } else if (wParam == IDM_SAVEDSESS) { + char *session = sessions[(lParam - IDM_SAVED_MIN) / 16]; + cl = malloc(16 + strlen(session)); /* 8, but play safe */ + if (!cl) + cl = NULL; /* not a very important failure mode */ + else { + sprintf(cl, "putty @%s", session); + freecl = TRUE; + } } else cl = NULL; @@ -642,6 +704,8 @@ static int WINAPI WndProc (HWND hwnd, UINT message, if (filemap) CloseHandle(filemap); + if (freecl) + free(cl); } break; case IDM_RECONF: @@ -658,6 +722,7 @@ static int WINAPI WndProc (HWND hwnd, UINT message, und_mode = UND_FONT; init_fonts(); sfree(logpal); + ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); if (pal) DeleteObject(pal); logpal = NULL; @@ -698,6 +763,10 @@ static int WINAPI WndProc (HWND hwnd, UINT message, case IDM_ABOUT: showabout (hwnd); break; + default: + if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) { + SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam); + } } break; @@ -727,8 +796,8 @@ static int WINAPI WndProc (HWND hwnd, UINT message, term_mouse (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND, MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); - return 0; ReleaseCapture(); + return 0; case WM_RBUTTONDOWN: SetCapture(hwnd); click (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE, @@ -824,6 +893,12 @@ static int WINAPI WndProc (HWND hwnd, UINT message, case WM_IGNORE_SIZE: ignore_size = TRUE; /* don't panic on next WM_SIZE msg */ break; + case WM_ENTERSIZEMOVE: + EnableSizeTip(1); + break; + case WM_EXITSIZEMOVE: + EnableSizeTip(0); + break; case WM_SIZING: { int width, height, w, h, ew, eh; @@ -833,6 +908,7 @@ static int WINAPI WndProc (HWND hwnd, UINT message, height = r->bottom - r->top - extra_height; w = (width + font_width/2) / font_width; if (w < 1) w = 1; h = (height + font_height/2) / font_height; if (h < 1) h = 1; + UpdateSizeTip(hwnd, w, h); ew = width - w * font_width; eh = height - h * font_height; if (ew != 0) { @@ -866,7 +942,10 @@ static int WINAPI WndProc (HWND hwnd, UINT message, if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText (hwnd, window_name); if (!ignore_size) { - int width, height, w, h, ew, eh; + int width, height, w, h; +#if 0 /* we have fixed this using WM_SIZING now */ + int ew, eh; +#endif width = LOWORD(lParam); height = HIWORD(lParam); @@ -947,9 +1026,38 @@ static int WINAPI WndProc (HWND hwnd, UINT message, int len; len = TranslateKey (wParam, lParam, buf); - back->send (buf, len); + if (len == -1) + return DefWindowProc (hwnd, message, wParam, lParam); + ldisc->send (buf, len); } return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + /* + * We handle KEYUP ourselves in order to distinghish left + * and right Alt or Control keys, which Windows won't do + * right if left to itself. See also the special processing + * at the top of TranslateKey. + */ + { + BYTE keystate[256]; + int ret = GetKeyboardState(keystate); + if (ret && wParam == VK_MENU) { + if (lParam & 0x1000000) keystate[VK_RMENU] = 0; + else keystate[VK_LMENU] = 0; + SetKeyboardState (keystate); + } + if (ret && wParam == VK_CONTROL) { + if (lParam & 0x1000000) keystate[VK_RCONTROL] = 0; + else keystate[VK_LCONTROL] = 0; + SetKeyboardState (keystate); + } + } + /* + * We don't return here, in order to allow Windows to do + * its own KEYUP processing as well. + */ + break; case WM_CHAR: case WM_SYSCHAR: /* @@ -959,8 +1067,8 @@ static int WINAPI WndProc (HWND hwnd, UINT message, * we're ready to cope. */ { - char c = wParam; - back->send (&c, 1); + char c = xlat_kbd2tty((unsigned char)wParam); + ldisc->send (&c, 1); } return 0; } @@ -1084,18 +1192,24 @@ void do_text (Context ctx, int x, int y, char *text, int len, TextOut (hdc, x-1, y, text, len); } if (und_mode == UND_LINE && (attr & ATTR_UNDER)) { - SelectObject (hdc, CreatePen(PS_SOLID, 0, fg)); + HPEN oldpen; + oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, fg)); MoveToEx (hdc, x, y+descent, NULL); LineTo (hdc, x+len*font_width, y+descent); + oldpen = SelectObject (hdc, oldpen); + DeleteObject (oldpen); } if (attr & ATTR_PASCURS) { POINT pts[5]; + HPEN oldpen; pts[0].x = pts[1].x = pts[4].x = x; pts[2].x = pts[3].x = x+font_width-1; pts[0].y = pts[3].y = pts[4].y = y; pts[1].y = pts[2].y = y+font_height-1; - SelectObject (hdc, CreatePen(PS_SOLID, 0, colours[23])); + oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, colours[23])); Polyline (hdc, pts, 5); + oldpen = SelectObject (hdc, oldpen); + DeleteObject (oldpen); } } @@ -1107,18 +1221,71 @@ static int TranslateKey(WPARAM wParam, LPARAM lParam, unsigned char *output) { unsigned char *p = output; BYTE keystate[256]; int ret, code; + int cancel_alt = FALSE; + + /* + * Get hold of the keyboard state, because we'll need it a few + * times shortly. + */ + ret = GetKeyboardState(keystate); + + /* + * Record that we pressed key so the scroll window can be reset, but + * be careful to avoid Shift-UP/Down + */ + if( wParam != VK_SHIFT && wParam != VK_PRIOR && wParam != VK_NEXT ) { + seen_key_event = 1; + } + + /* + * Windows does not always want to distinguish left and right + * Alt or Control keys. Thus we keep track of them ourselves. + * See also the WM_KEYUP handler. + */ + if (wParam == VK_MENU) { + if (lParam & 0x1000000) keystate[VK_RMENU] = 0x80; + else keystate[VK_LMENU] = 0x80; + SetKeyboardState (keystate); + return 0; + } + if (wParam == VK_CONTROL) { + if (lParam & 0x1000000) keystate[VK_RCONTROL] = 0x80; + else keystate[VK_LCONTROL] = 0x80; + SetKeyboardState (keystate); + return 0; + } /* - * Prepend ESC if ALT was pressed at the time. + * Prepend ESC, and cancel ALT, if ALT was pressed at the time + * and it wasn't AltGr. */ - if (lParam & 0x20000000) + if (lParam & 0x20000000 && (keystate[VK_LMENU] & 0x80)) { *p++ = 0x1B; + cancel_alt = TRUE; + } /* - * Get hold of the keyboard state, because we'll need it a few - * times shortly. + * NetHack keypad mode. This may conflict with Shift-PgUp/PgDn, + * so we do it first. */ - ret = GetKeyboardState(keystate); + if (cfg.nethack_keypad) { + int shift = keystate[VK_SHIFT] & 0x80; + /* + * NB the shifted versions only work with numlock off. + */ + switch ( (lParam >> 16) & 0x1FF ) { + case 0x047: *p++ = shift ? 'Y' : 'y'; return p - output; + case 0x048: *p++ = shift ? 'K' : 'k'; return p - output; + case 0x049: *p++ = shift ? 'U' : 'u'; return p - output; + case 0x04B: *p++ = shift ? 'H' : 'h'; return p - output; + case 0x04C: *p++ = '.'; return p - output; + case 0x04D: *p++ = shift ? 'L' : 'l'; return p - output; + case 0x04F: *p++ = shift ? 'B' : 'b'; return p - output; + case 0x050: *p++ = shift ? 'J' : 'j'; return p - output; + case 0x051: *p++ = shift ? 'N' : 'n'; return p - output; + case 0x053: *p++ = '.'; return p - output; + } + } /* * Shift-PgUp, Shift-PgDn, and Alt-F4 all produce window @@ -1132,9 +1299,12 @@ static int TranslateKey(WPARAM wParam, LPARAM lParam, unsigned char *output) { SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); return 0; } - if ((lParam & 0x20000000) && wParam == VK_F4) { - SendMessage (hwnd, WM_DESTROY, 0, 0); - return 0; + if ((lParam & 0x20000000) && wParam == VK_F4 && cfg.alt_f4) { + return -1; + } + if ((lParam & 0x20000000) && wParam == VK_SPACE && cfg.alt_space) { + SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); + return -1; } /* @@ -1160,12 +1330,12 @@ static int TranslateKey(WPARAM wParam, LPARAM lParam, unsigned char *output) { return p - output; } - /* - * If we're in applications keypad mode, we have to process it - * before char-map translation, because it will pre-empt lots - * of stuff, even if NumLock is off. - */ if (app_keypad_keys) { + /* + * If we're in applications keypad mode, we have to process it + * before char-map translation, because it will pre-empt lots + * of stuff, even if NumLock is off. + */ if (ret) { /* * Hack to ensure NumLock doesn't interfere with @@ -1203,23 +1373,36 @@ static int TranslateKey(WPARAM wParam, LPARAM lParam, unsigned char *output) { } /* - * Before doing Windows charmap translation, remove ALT from - * the keymap, since its sole effect should be to prepend ESC, - * which we've already done. Note that removal of ALT has to - * happen _after_ the above call to SetKeyboardState, or dire - * things will befall. + * Before doing Windows charmap translation, remove LeftALT + * from the keymap, since its sole effect should be to prepend + * ESC, which we've already done. Note that removal of LeftALT + * has to happen _after_ the above call to SetKeyboardState, or + * dire things will befall. */ - keystate[VK_MENU] = keystate[VK_LMENU] = keystate[VK_RMENU] = 0; + if (cancel_alt) { + keystate[VK_MENU] = keystate[VK_RMENU]; + keystate[VK_LMENU] = 0; + } /* * Attempt the Windows char-map translation. */ if (ret) { WORD chr; - int r = ToAscii (wParam, (lParam >> 16) & 0xFF, - keystate, &chr, 0); + int r; + BOOL capsOn=keystate[VK_CAPITAL] !=0; + + /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ + if(cfg.xlat_capslockcyr) + keystate[VK_CAPITAL] = 0; + + r = ToAscii (wParam, (lParam >> 16) & 0xFF, + keystate, &chr, 0); + + if(capsOn) + chr = xlat_latkbd2win((unsigned char)(chr & 0xFF)); if (r == 1) { - *p++ = chr & 0xFF; + *p++ = xlat_kbd2tty((unsigned char)(chr & 0xFF)); return p - output; } } @@ -1347,10 +1530,11 @@ void set_sbar (int total, int start, int page) { si.nMax = total - 1; si.nPage = page; si.nPos = start; - SetScrollInfo (hwnd, SB_VERT, &si, TRUE); + if (hwnd) + SetScrollInfo (hwnd, SB_VERT, &si, TRUE); } -Context get_ctx() { +Context get_ctx(void) { HDC hdc; if (hwnd) { hdc = GetDC (hwnd); @@ -1478,11 +1662,10 @@ void get_clip (void **p, int *len) { */ void optimised_move (int to, int from, int lines) { RECT r; - int min, max, d; + int min, max; min = (to < from ? to : from); max = to + from - min; - d = max - min; r.left = 0; r.right = cols * font_width; r.top = min * font_height; r.bottom = (max+lines) * font_height;