X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/0c50ef57baa8c64b7983589604346605fd1b5290..0965bee0865fd8ea129b2de62a3c50e09c59a184:/window.c diff --git a/window.c b/window.c index 47ca0893..cef6825f 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,5 @@ #include +#include #include #ifndef AUTO_WINSOCK #ifdef WINSOCK_TWO @@ -10,9 +11,11 @@ #include #include #include +#include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" +#include "winstuff.h" #include "storage.h" #include "win_res.h" @@ -37,6 +40,7 @@ #define IDM_TEL_EOF 0x0130 #define IDM_ABOUT 0x0140 #define IDM_SAVEDSESS 0x0150 +#define IDM_COPYALL 0x0160 #define IDM_SAVED_MIN 0x1000 #define IDM_SAVED_MAX 0x2000 @@ -44,6 +48,11 @@ #define WM_IGNORE_SIZE (WM_XUSER + 1) #define WM_IGNORE_CLIP (WM_XUSER + 2) +/* Needed for Chinese support and apparently not always defined. */ +#ifndef VK_PROCESSKEY +#define VK_PROCESSKEY 0xE5 +#endif + static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output); static void cfgtopalette(void); @@ -57,6 +66,8 @@ static WPARAM pend_netevent_wParam = 0; static LPARAM pend_netevent_lParam = 0; static void enact_pending_netevent(void); +static time_t last_movement = 0; + #define FONT_NORMAL 0 #define FONT_BOLD 1 #define FONT_UNDERLINE 2 @@ -90,11 +101,10 @@ static Mouse_Button lastbtn; static char *window_name, *icon_name; -static Ldisc *real_ldisc; +static int compose_state = 0; -void begin_session(void) { - ldisc = real_ldisc; -} +/* Dummy routine, only required in plink. */ +void ldisc_update(int echo, int edit) {} int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { static char appname[] = "PuTTY"; @@ -104,7 +114,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { MSG msg; int guess_width, guess_height; - putty_inst = inst; + hinst = inst; flags = FLAG_VERBOSE | FLAG_INTERACTIVE; winsock_ver = MAKEWORD(1, 1); @@ -120,9 +130,14 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { return 1; } /* WISHLIST: maybe allow config tweaking even if winsock not present? */ + sk_init(); InitCommonControls(); + /* Ensure a Maximize setting in Explorer doesn't maximise the + * config box. */ + defuse_showwindow(); + /* * Process the command line. */ @@ -131,6 +146,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { default_protocol = DEFAULT_PROTOCOL; default_port = DEFAULT_PORT; + cfg.logtype = LGTYP_NONE; do_defaults(NULL, &cfg); @@ -151,11 +167,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { tolower(p[2]) == 'h') { default_protocol = cfg.protocol = PROT_SSH; default_port = cfg.port = 22; - } else if (q == p + 3 && - tolower(p[0]) == 'l' && - tolower(p[1]) == 'o' && - tolower(p[2]) == 'g') { - logfile = "putty.log"; } else if (q == p + 7 && tolower(p[0]) == 'c' && tolower(p[1]) == 'l' && @@ -190,6 +201,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { * An initial @ means to activate a saved session. */ 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()) { WSACleanup(); @@ -292,10 +307,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } } - real_ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); - /* To start with, we use the simple line discipline, so we can - * type passwords etc without fear of them being echoed... */ - ldisc = &ldisc_simple; + /* Check for invalid Port number (i.e. zero) */ + if (cfg.port == 0) { + MessageBox(NULL, "Invalid Port Number", + "PuTTY Internal Error", MB_OK |MB_ICONEXCLAMATION); + WSACleanup(); + return 1; + } if (!prev) { wndclass.style = 0; @@ -345,15 +363,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } { - int winmode = WS_OVERLAPPEDWINDOW|WS_VSCROLL; - if (!cfg.scrollbar) winmode &= ~(WS_VSCROLL); - if (cfg.locksize) winmode &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX); - hwnd = CreateWindow (appname, appname, - winmode, - CW_USEDEFAULT, CW_USEDEFAULT, - guess_width, guess_height, - NULL, NULL, inst, NULL); - } + int winmode = WS_OVERLAPPEDWINDOW|WS_VSCROLL; + int exwinmode = 0; + if (!cfg.scrollbar) winmode &= ~(WS_VSCROLL); + if (cfg.locksize) winmode &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX); + if (cfg.alwaysontop) exwinmode = WS_EX_TOPMOST; + hwnd = CreateWindowEx (exwinmode, appname, appname, + winmode, CW_USEDEFAULT, CW_USEDEFAULT, + guess_width, guess_height, + NULL, NULL, inst, NULL); + } /* * Initialise the fonts, simultaneously correcting the guesses @@ -390,10 +409,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { { char *bits; int size = (font_width+15)/16 * 2 * font_height; - bits = calloc(size, 1); + bits = smalloc(size); + memset(bits, 0, size); caretbm = CreateBitmap(font_width, font_height, 1, 1, bits); - free(bits); + sfree(bits); } + CreateCaret(hwnd, caretbm, font_width, font_height); /* * Initialise the scroll bar. @@ -418,7 +439,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { char msg[1024], *title; char *realhost; - error = back->init (hwnd, cfg.host, cfg.port, &realhost); + error = back->init (cfg.host, cfg.port, &realhost); if (error) { sprintf(msg, "Unable to open connection:\n%s", error); MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK); @@ -482,15 +503,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } AppendMenu (m, MF_ENABLED, IDM_SHOWLOG, "&Event Log"); AppendMenu (m, MF_SEPARATOR, 0, 0); - AppendMenu (m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session"); + AppendMenu (m, MF_ENABLED, IDM_NEWSESS, "Ne&w 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, "Sa&ved Sessions"); - AppendMenu (m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings"); + AppendMenu (m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu (m, MF_SEPARATOR, 0, 0); + AppendMenu (m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard"); AppendMenu (m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback"); AppendMenu (m, MF_ENABLED, IDM_RESET, "Rese&t Terminal"); AppendMenu (m, MF_SEPARATOR, 0, 0); @@ -503,6 +525,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { ShowWindow (hwnd, show); /* + * Open the initial log file if there is one. + */ + logfopen(); + + /* * Set the palette up. */ pal = NULL; @@ -512,10 +539,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { has_focus = (GetForegroundWindow() == hwnd); UpdateWindow (hwnd); + if (GetMessage (&msg, NULL, 0, 0) == 1) { int timer_id = 0, long_timer = 0; - while (GetMessage (&msg, NULL, 0, 0) == 1) { + while (msg.message != WM_QUIT) { /* Sometimes DispatchMessage calls routines that use their own * GetMessage loop, setup this timer so we get some control back. * @@ -528,11 +556,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } if(!timer_id) timer_id = SetTimer(hwnd, 1, 20, NULL); - DispatchMessage (&msg); + if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg))) + DispatchMessage (&msg); - /* This is too fast, but I'll leave it for now 'cause it shows - * how often term_update is called (far too often at times!) - */ + /* Make sure we blink everything that needs it. */ term_blink(0); /* Send the paste buffer if there's anything to send */ @@ -542,31 +569,44 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { * we've delayed, reading the socket, writing, and repainting * the window. */ - if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { - if (pending_netevent) { - enact_pending_netevent(); + if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + continue; - term_blink(1); - } - } else continue; - if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { - if (timer_id) { - KillTimer(hwnd, timer_id); - timer_id = 0; - } - HideCaret(hwnd); - if (inbuf_head) - term_out(); - term_update(); - ShowCaret(hwnd); - if (!has_focus) - timer_id = SetTimer(hwnd, 1, 2000, NULL); - else if (cfg.blinktext) - timer_id = SetTimer(hwnd, 1, 250, NULL); - else - timer_id = SetTimer(hwnd, 1, 500, NULL); - long_timer = 1; + if (pending_netevent) { + enact_pending_netevent(); + + /* Force the cursor blink on */ + term_blink(1); + + if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + continue; + } + + /* Okay there is now nothing to do so we make sure the screen is + * completely up to date then tell windows to call us in a little + * while. + */ + if (timer_id) { + KillTimer(hwnd, timer_id); + timer_id = 0; } + HideCaret(hwnd); + if (inbuf_head) + term_out(); + term_update(); + ShowCaret(hwnd); + if (!has_focus) + timer_id = SetTimer(hwnd, 1, 59500, NULL); + else + timer_id = SetTimer(hwnd, 1, 100, NULL); + long_timer = 1; + + /* There's no point rescanning everything in the message queue + * so we do an apperently unneccesary wait here + */ + WaitMessage(); + if (GetMessage (&msg, NULL, 0, 0) != 1) + break; } } @@ -595,6 +635,28 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } /* + * Set up, or shut down, an AsyncSelect. Called from winnet.c. + */ +char *do_select(SOCKET skt, int startup) { + int msg, events; + if (startup) { + msg = WM_NETEVENT; + events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE; + } else { + msg = events = 0; + } + if (!hwnd) + return "do_select(): internal error (hwnd==NULL)"; + if (WSAAsyncSelect (skt, hwnd, msg, events) == SOCKET_ERROR) { + switch (WSAGetLastError()) { + case WSAENETDOWN: return "Network is down"; + default: return "WSAAsyncSelect(): unknown error"; + } + } + return NULL; +} + +/* * Print a message box and close the connection. */ void connection_fatal(char *fmt, ...) { @@ -617,8 +679,9 @@ void connection_fatal(char *fmt, ...) { * Actually do the job requested by a WM_NETEVENT */ static void enact_pending_netevent(void) { - int i; static int reentering = 0; + extern int select_result(WPARAM, LPARAM); + int ret; if (reentering) return; /* don't unpend the pending */ @@ -626,22 +689,10 @@ static void enact_pending_netevent(void) { pending_netevent = FALSE; reentering = 1; - i = back->msg (pend_netevent_wParam, pend_netevent_lParam); + ret = select_result (pend_netevent_wParam, pend_netevent_lParam); reentering = 0; - if (i < 0) { - char buf[1024]; - switch (WSABASEERR + (-i) % 10000) { - case WSAECONNRESET: - sprintf(buf, "Connection reset by peer"); - break; - default: - sprintf(buf, "Unexpected network error %d", -i); - break; - } - connection_fatal(buf); - } - if (i <= 0) { + if (ret == 0) { if (cfg.close_on_exit) PostQuitMessage(0); else { @@ -745,7 +796,7 @@ font_messup: if (cfg.fontisbold) { fw_dontcare = FW_BOLD; - fw_bold = FW_BLACK; + fw_bold = FW_HEAVY; } else { fw_dontcare = FW_DONTCARE; fw_bold = FW_BOLD; @@ -996,6 +1047,17 @@ static void click (Mouse_Button b, int x, int y) { lasttime = thistime; } +static void show_mouseptr(int show) { + static int cursor_visible = 1; + if (!cfg.hide_mouseptr) /* override if this feature disabled */ + show = 1; + if (cursor_visible && !show) + ShowCursor(FALSE); + else if (!cursor_visible && show) + ShowCursor(TRUE); + cursor_visible = show; +} + static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; @@ -1003,6 +1065,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, static int ignore_clip = FALSE; static int just_reconfigged = FALSE; static int resizing = FALSE; + static int need_backend_resize = FALSE; switch (message) { case WM_TIMER: @@ -1010,13 +1073,25 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, enact_pending_netevent(); if (inbuf_head) term_out(); + noise_regular(); HideCaret(hwnd); term_update(); ShowCaret(hwnd); + if (cfg.ping_interval > 0) + { + time_t now; + time(&now); + if (now-last_movement > cfg.ping_interval) + { + back->special(TS_PING); + last_movement = now; + } + } return 0; case WM_CREATE: break; case WM_CLOSE: + show_mouseptr(1); if (!cfg.warn_on_close || session_closed || MessageBox(hwnd, "Are you sure you want to close this session?", "PuTTY Exit Confirmation", @@ -1024,6 +1099,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, DestroyWindow(hwnd); return 0; case WM_DESTROY: + show_mouseptr(1); PostQuitMessage (0); return 0; case WM_SYSCOMMAND: @@ -1072,7 +1148,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, cl = c; } else if (wParam == IDM_SAVEDSESS) { char *session = sessions[(lParam - IDM_SAVED_MIN) / 16]; - cl = malloc(16 + strlen(session)); /* 8, but play safe */ + cl = smalloc(16 + strlen(session)); /* 8, but play safe */ if (!cl) cl = NULL; /* not a very important failure mode */ else { @@ -1096,82 +1172,139 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, if (filemap) CloseHandle(filemap); if (freecl) - free(cl); + sfree(cl); } break; - case IDM_RECONF: - if (!do_reconfig(hwnd)) - break; - just_reconfigged = TRUE; - { - int i; - for (i=0; i<8; i++) - if (fonts[i]) - DeleteObject(fonts[i]); - } - bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; - und_mode = UND_FONT; - init_fonts(0); - sfree(logpal); - /* Telnet will change local echo -> remote if the remote asks */ - if (cfg.protocol != PROT_TELNET) - ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); - if (pal) - DeleteObject(pal); - logpal = NULL; - pal = NULL; - cfgtopalette(); - init_palette(); - - /* Enable or disable the scroll bar, etc */ - { - LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE); + case IDM_RECONF: + { + int prev_alwaysontop = cfg.alwaysontop; + char oldlogfile[FILENAME_MAX]; + int oldlogtype; + int need_setwpos = FALSE; + int old_fwidth, old_fheight; + + strcpy(oldlogfile, cfg.logfilename); + oldlogtype = cfg.logtype; + cfg.width = cols; + cfg.height = rows; + old_fwidth = font_width; + old_fheight = font_height; + GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); + + if (!do_reconfig(hwnd)) + break; + + if (strcmp(oldlogfile, cfg.logfilename) || + oldlogtype != cfg.logtype) { + logfclose(); /* reset logging */ + logfopen(); + } - nflg = flag; - if (cfg.scrollbar) nflg |= WS_VSCROLL; - else nflg &= ~WS_VSCROLL; - if (cfg.locksize) - nflg &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX); - else - nflg |= (WS_THICKFRAME|WS_MAXIMIZEBOX); + just_reconfigged = TRUE; + { + int i; + for (i=0; i<8; i++) + if (fonts[i]) + DeleteObject(fonts[i]); + } + bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; + und_mode = UND_FONT; + init_fonts(0); + sfree(logpal); + /* + * Flush the line discipline's edit buffer in the + * case where local editing has just been disabled. + */ + ldisc_send(NULL, 0); + if (pal) + DeleteObject(pal); + logpal = NULL; + pal = NULL; + cfgtopalette(); + init_palette(); + + /* Enable or disable the scroll bar, etc */ + { + LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE); + LONG nexflag, exflag = GetWindowLong(hwnd, GWL_EXSTYLE); + + nexflag = exflag; + if (cfg.alwaysontop != prev_alwaysontop) { + if (cfg.alwaysontop) { + nexflag = WS_EX_TOPMOST; + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + } else { + nexflag = 0; + SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + } + } + + nflg = flag; + if (cfg.scrollbar) nflg |= WS_VSCROLL; + else nflg &= ~WS_VSCROLL; + if (cfg.locksize) + nflg &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX); + else + nflg |= (WS_THICKFRAME|WS_MAXIMIZEBOX); + + if (nflg != flag || nexflag != exflag) + { + RECT cr, wr; + + if (nflg != flag) + SetWindowLong(hwnd, GWL_STYLE, nflg); + if (nexflag != exflag) + SetWindowLong(hwnd, GWL_EXSTYLE, nexflag); + + SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0); + + SetWindowPos(hwnd, NULL, 0,0,0,0, + SWP_NOACTIVATE|SWP_NOCOPYBITS| + SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER| + SWP_FRAMECHANGED); + + GetWindowRect (hwnd, &wr); + GetClientRect (hwnd, &cr); + extra_width = wr.right - wr.left - cr.right + cr.left; + extra_height = wr.bottom - wr.top - cr.bottom + cr.top; + } + } - if (nflg != flag) - { - RECT cr, wr; - - SetWindowLong(hwnd, GWL_STYLE, nflg); - SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0); - SetWindowPos(hwnd, NULL, 0,0,0,0, - SWP_NOACTIVATE|SWP_NOCOPYBITS| - SWP_NOMOVE|SWP_NOSIZE| SWP_NOZORDER| - SWP_FRAMECHANGED); - - GetWindowRect (hwnd, &wr); - GetClientRect (hwnd, &cr); - extra_width = wr.right - wr.left - cr.right + cr.left; - extra_height = wr.bottom - wr.top - cr.bottom + cr.top; + if (cfg.height != rows || + cfg.width != cols || + old_fwidth != font_width || + old_fheight != font_height || + cfg.savelines != savelines) + need_setwpos = TRUE; + term_size(cfg.height, cfg.width, cfg.savelines); + InvalidateRect(hwnd, NULL, TRUE); + if (need_setwpos) { + force_normal(hwnd); + SetWindowPos (hwnd, NULL, 0, 0, + extra_width + font_width * cfg.width, + extra_height + font_height * cfg.height, + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOMOVE | SWP_NOZORDER); } - } - - term_size(cfg.height, cfg.width, cfg.savelines); - InvalidateRect(hwnd, NULL, TRUE); - SetWindowPos (hwnd, NULL, 0, 0, - extra_width + font_width * cfg.width, - extra_height + font_height * cfg.height, - SWP_NOACTIVATE | SWP_NOCOPYBITS | - SWP_NOMOVE | SWP_NOZORDER); - if (IsIconic(hwnd)) { - SetWindowText (hwnd, - cfg.win_name_always ? window_name : icon_name); - } - break; - case IDM_CLRSB: - term_clrsb(); - break; - case IDM_RESET: - term_pwron(); + set_title(cfg.wintitle); + if (IsIconic(hwnd)) { + SetWindowText (hwnd, + cfg.win_name_always ? window_name : icon_name); + } + } + break; + case IDM_COPYALL: + term_copyall(); break; - case IDM_TEL_AYT: back->special (TS_AYT); break; + case IDM_CLRSB: + term_clrsb(); + break; + case IDM_RESET: + term_pwron(); + break; + case IDM_TEL_AYT: back->special (TS_AYT); break; case IDM_TEL_BRK: back->special (TS_BRK); break; case IDM_TEL_SYNCH: back->special (TS_SYNCH); break; case IDM_TEL_EC: back->special (TS_EC); break; @@ -1201,46 +1334,52 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, #define TO_CHR_Y(y) (((y)<0 ? (y)-font_height+1: (y)) / font_height) case WM_LBUTTONDOWN: + show_mouseptr(1); click (MB_SELECT, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); SetCapture(hwnd); return 0; case WM_LBUTTONUP: + show_mouseptr(1); term_mouse (MB_SELECT, MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); ReleaseCapture(); return 0; case WM_MBUTTONDOWN: + show_mouseptr(1); SetCapture(hwnd); click (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); return 0; case WM_MBUTTONUP: + show_mouseptr(1); term_mouse (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND, MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); ReleaseCapture(); return 0; case WM_RBUTTONDOWN: + show_mouseptr(1); SetCapture(hwnd); click (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); return 0; case WM_RBUTTONUP: + show_mouseptr(1); term_mouse (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE, MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); ReleaseCapture(); return 0; case WM_MOUSEMOVE: + show_mouseptr(1); /* * Add the mouse position and message time to the random - * number noise, if we're using ssh. + * number noise. */ - if (cfg.protocol == PROT_SSH) - noise_ultralight(lParam); + noise_ultralight(lParam); if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) { Mouse_Button b; @@ -1290,15 +1429,18 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, pending_netevent = TRUE; pend_netevent_wParam=wParam; pend_netevent_lParam=lParam; + time(&last_movement); return 0; case WM_SETFOCUS: has_focus = TRUE; - CreateCaret(hwnd, caretbm, 0, 0); + CreateCaret(hwnd, caretbm, font_width, font_height); ShowCaret(hwnd); + compose_state = 0; term_out(); term_update(); break; case WM_KILLFOCUS: + show_mouseptr(1); has_focus = FALSE; DestroyCaret(); term_out(); @@ -1310,11 +1452,13 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, case WM_ENTERSIZEMOVE: EnableSizeTip(1); resizing = TRUE; + need_backend_resize = FALSE; break; case WM_EXITSIZEMOVE: EnableSizeTip(0); resizing = FALSE; - back->size(); + if (need_backend_resize) + back->size(); break; case WM_SIZING: { @@ -1390,6 +1534,8 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, */ if (!resizing) back->size(); + else + need_backend_resize = TRUE; just_reconfigged = FALSE; } } @@ -1434,10 +1580,9 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, case WM_SYSKEYUP: /* * Add the scan code and keypress timing to the random - * number noise, if we're using ssh. + * number noise. */ - if (cfg.protocol == PROT_SSH) - noise_ultralight(lParam); + noise_ultralight(lParam); /* * We don't do TranslateMessage since it disassociates the @@ -1450,12 +1595,32 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, unsigned char buf[20]; int len; - len = TranslateKey (message, wParam, lParam, buf); - if (len == -1) - return DefWindowProc (hwnd, message, wParam, lParam); - ldisc->send (buf, len); + if (wParam==VK_PROCESSKEY) { + MSG m; + m.hwnd = hwnd; + m.message = WM_KEYDOWN; + m.wParam = wParam; + m.lParam = lParam & 0xdfff; + TranslateMessage(&m); + } else { + len = TranslateKey (message, wParam, lParam, buf); + if (len == -1) + return DefWindowProc (hwnd, message, wParam, lParam); + ldisc_send (buf, len); + + if (len > 0) + show_mouseptr(0); + } } return 0; + case WM_IME_CHAR: + { + unsigned char buf[2]; + + buf[1] = wParam; + buf[0] = wParam >> 8; + ldisc_send (buf, 2); + } case WM_CHAR: case WM_SYSCHAR: /* @@ -1466,7 +1631,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, */ { char c = xlat_kbd2tty((unsigned char)wParam); - ldisc->send (&c, 1); + ldisc_send (&c, 1); } return 0; } @@ -1514,7 +1679,7 @@ void do_text (Context ctx, int x, int y, char *text, int len, x *= fnt_width; y *= font_height; - if (attr & ATTR_ACTCURS) { + if ((attr & ATTR_ACTCURS) && cfg.cursor_type == 0) { attr &= (bold_mode == BOLD_COLOURS ? 0x300200 : 0x300300); attr ^= ATTR_CUR_XOR; } @@ -1569,16 +1734,7 @@ void do_text (Context ctx, int x, int y, char *text, int len, } } - if (attr & ATTR_GBCHR) { - int i; - /* - * GB mapping: map # to pound, and everything else stays - * normal. - */ - for (i=0; i= VK_F1 && wParam <= VK_F20 ) + debug(("K_F%d", wParam+1-VK_F1)); + else switch(wParam) + { + case VK_SHIFT: debug(("SHIFT")); break; + case VK_CONTROL: debug(("CTRL")); break; + case VK_MENU: debug(("ALT")); break; + default: debug(("VK_%02x", wParam)); + } + if(message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) + debug(("*")); + debug((", S%02x", scan=(HIWORD(lParam) & 0xFF) )); + + ch = MapVirtualKeyEx(wParam, 2, kbd_layout); + if (ch>=' ' && ch<='~') debug((", '%c'", ch)); + else if (ch) debug((", $%02x", ch)); + + if (keys[0]) debug((", KB0=%02x", keys[0])); + if (keys[1]) debug((", KB1=%02x", keys[1])); + if (keys[2]) debug((", KB2=%02x", keys[2])); + + if ( (keystate[VK_SHIFT]&0x80)!=0) debug((", S")); + if ( (keystate[VK_CONTROL]&0x80)!=0) debug((", C")); + if ( (HIWORD(lParam)&KF_EXTENDED) ) debug((", E")); + if ( (HIWORD(lParam)&KF_UP) ) debug((", U")); + } + + if ((HIWORD(lParam)&(KF_UP|KF_REPEAT))==KF_REPEAT) + ; + else if ( (HIWORD(lParam)&KF_UP) ) + oldstate[wParam&0xFF] ^= 0x80; + else + oldstate[wParam&0xFF] ^= 0x81; + + for(ch=0; ch<256; ch++) + if (oldstate[ch] != keystate[ch]) + debug((", M%02x=%02x", ch, keystate[ch])); + + memcpy(oldstate, keystate, sizeof(oldstate)); + } +#endif + + if (wParam == VK_MENU && (HIWORD(lParam)&KF_EXTENDED)) { keystate[VK_RMENU] = keystate[VK_MENU]; - if (!compose_state) compose_key = wParam; } - if (wParam == VK_APPS && !compose_state) - compose_key = wParam; - if (wParam == compose_key) - { - if (compose_state == 0 && (HIWORD(lParam)&(KF_UP|KF_REPEAT))==0) - compose_state = 1; - else if (compose_state == 1 && (HIWORD(lParam)&KF_UP)) - compose_state = 2; - else - compose_state = 0; + /* Note if AltGr was pressed and if it was used as a compose key */ + if (cfg.compose_key) { + if (wParam == VK_MENU && (HIWORD(lParam)&KF_EXTENDED)) + { + if (!compose_state) compose_key = wParam; + } + if (wParam == VK_APPS && !compose_state) + compose_key = wParam; + + if (wParam == compose_key) + { + if (compose_state == 0 && (HIWORD(lParam)&(KF_UP|KF_REPEAT))==0) + compose_state = 1; + else if (compose_state == 1 && (HIWORD(lParam)&KF_UP)) + compose_state = 2; + else + compose_state = 0; + } + else if (compose_state==1 && wParam != VK_CONTROL) + compose_state = 0; + } else { + compose_state = 0; } - else if (compose_state==1 && wParam != VK_CONTROL) - compose_state = 0; /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ - if ( (cfg.funky_type == 0 || (cfg.funky_type == 1 && app_keypad_keys)) + if ( (cfg.funky_type == 3 || + (cfg.funky_type <= 1 && app_keypad_keys && !cfg.no_applic_k)) && wParam==VK_NUMLOCK && !(keystate[VK_SHIFT]&0x80)) { wParam = VK_EXECUTE; @@ -1834,8 +2079,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha if (compose_state>1 && left_alt) compose_state = 0; /* Sanitize the number pad if not using a PC NumPad */ - if( left_alt || (app_keypad_keys && cfg.funky_type != 2) - || cfg.nethack_keypad || compose_state ) + if( left_alt || (app_keypad_keys && !cfg.no_applic_k + && cfg.funky_type != 2) + || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state ) { if ((HIWORD(lParam)&KF_EXTENDED) == 0) { @@ -1886,10 +2132,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha return -1; } if (left_alt && wParam == VK_SPACE && cfg.alt_space) { - + alt_state = 0; + PostMessage(hwnd, WM_CHAR, ' ', 0); SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); return -1; } + /* Control-Numlock for app-keypad mode switch */ + if (wParam == VK_PAUSE && shift_state == 2) { + app_keypad_keys ^= 1; + return 0; + } /* Nethack keypad */ if (cfg.nethack_keypad && !left_alt) { @@ -1910,14 +2162,15 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha if (!left_alt) { int xkey = 0; - if ( cfg.funky_type == 0 || - ( cfg.funky_type == 1 && app_keypad_keys)) switch(wParam) { - case VK_EXECUTE: if (app_keypad_keys) xkey = 'P'; break; + if ( cfg.funky_type == 3 || + ( cfg.funky_type <= 1 && + app_keypad_keys && !cfg.no_applic_k)) switch(wParam) { + case VK_EXECUTE: xkey = 'P'; break; case VK_DIVIDE: xkey = 'Q'; break; case VK_MULTIPLY:xkey = 'R'; break; case VK_SUBTRACT:xkey = 'S'; break; } - if(app_keypad_keys) switch(wParam) { + if(app_keypad_keys && !cfg.no_applic_k) switch(wParam) { case VK_NUMPAD0: xkey = 'p'; break; case VK_NUMPAD1: xkey = 'q'; break; case VK_NUMPAD2: xkey = 'r'; break; @@ -1930,9 +2183,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha case VK_NUMPAD9: xkey = 'y'; break; case VK_DECIMAL: xkey = 'n'; break; - case VK_ADD: if(shift_state) xkey = 'm'; - else xkey = 'l'; + case VK_ADD: if(cfg.funky_type==2) { + if(shift_state) xkey = 'l'; + else xkey = 'k'; + } else if(shift_state) xkey = 'm'; + else xkey = 'l'; break; + + case VK_DIVIDE: if(cfg.funky_type==2) xkey = 'o'; break; + case VK_MULTIPLY:if(cfg.funky_type==2) xkey = 'j'; break; + case VK_SUBTRACT:if(cfg.funky_type==2) xkey = 'm'; break; + case VK_RETURN: if (HIWORD(lParam)&KF_EXTENDED) xkey = 'M'; @@ -2031,12 +2292,18 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha case VK_PRIOR: code = 5; break; case VK_NEXT: code = 6; break; } + /* Reorder edit keys to physical order */ + if (cfg.funky_type == 3 && code <= 6 ) code = "\0\2\1\4\5\3\6"[code]; + if (cfg.funky_type == 1 && code >= 11 && code <= 15) { p += sprintf((char *)p, "\x1B[[%c", code + 'A' - 11); return p - output; } if (cfg.funky_type == 2 && code >= 11 && code <= 14) { - p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11); + if (vt52_mode) + p += sprintf((char *)p, "\x1B%c", code + 'P' - 11); + else + p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11); return p - output; } if (cfg.rxvt_homeend && (code == 1 || code == 4)) { @@ -2065,7 +2332,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha { if (vt52_mode) p += sprintf((char *)p, "\x1B%c", xkey); - else if (app_cursor_keys) + else if (app_cursor_keys && !cfg.no_applic_c) p += sprintf((char *)p, "\x1BO%c", xkey); else p += sprintf((char *)p, "\x1B[%c", xkey); @@ -2093,7 +2360,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha if(cfg.xlat_capslockcyr) keystate[VK_CAPITAL] = 0; - r = ToAscii (wParam, scan, keystate, keys, 0); + r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); if(r>0) { p = output; @@ -2112,7 +2379,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha if ((nc=check_compose(compose_char,ch)) == -1) { - c_write1('\007'); + MessageBeep(MB_ICONHAND); return 0; } *p++ = xlat_kbd2tty((unsigned char)nc); @@ -2139,11 +2406,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha } } - /* This stops ALT press-release doing a 'COMMAND MENU' function */ - if (message == WM_SYSKEYUP && wParam == VK_MENU) - { - keystate[VK_MENU] = 0; - return 0; + /* ALT alone may or may not want to bring up the System menu */ + if (wParam == VK_MENU) { + if (cfg.alt_only) { + if (message == WM_SYSKEYDOWN) + alt_state = 1; + else if (message == WM_SYSKEYUP && alt_state) + PostMessage(hwnd, WM_CHAR, ' ', 0); + if (message == WM_SYSKEYUP) + alt_state = 0; + } else + return 0; } return -1;