X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/9ca5da428c0113cced4401cc8c424eb6f485608a..8df7a775f6f8b0f81f84eafe28cd0bb8d4c6d1f4:/window.c diff --git a/window.c b/window.c index fe9d2e91..1e38a487 100644 --- a/window.c +++ b/window.c @@ -10,9 +10,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" @@ -44,6 +46,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 +64,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 @@ -104,7 +113,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 +129,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. */ @@ -132,7 +146,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { default_protocol = DEFAULT_PROTOCOL; default_port = DEFAULT_PORT; - do_defaults(NULL); + do_defaults(NULL, &cfg); p = cmdline; while (*p && isspace(*p)) p++; @@ -190,7 +204,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { * An initial @ means to activate a saved session. */ if (*p == '@') { - do_defaults (p+1); + 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(); return 0; @@ -345,14 +363,14 @@ 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; + 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); } /* @@ -418,7 +436,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); @@ -512,10 +530,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. * @@ -530,9 +549,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { timer_id = SetTimer(hwnd, 1, 20, NULL); 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 +559,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, 250, 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 +625,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 +669,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 +679,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 +786,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; @@ -1013,6 +1054,16 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, HideCaret(hwnd); term_update(); ShowCaret(hwnd); + if (cfg.ping_interval > 0) + { + time_t now; + time(&now); + if (now-last_movement > cfg.ping_interval * 60 - 10) + { + back->special(TS_PING); + last_movement = now; + } + } return 0; case WM_CREATE: break; @@ -1290,6 +1341,7 @@ 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; @@ -1450,12 +1502,29 @@ 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); + } } 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: /* @@ -1569,16 +1638,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 = MapVirtualKey(wParam, 2); + 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 + /* Note if AltGr was pressed and if it was used as a compose key */ - 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 (cfg.compose_key) { + 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; - } - else if (compose_state==1 && wParam != VK_CONTROL) - compose_state = 0; + 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; /* 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)) && wParam==VK_NUMLOCK && !(keystate[VK_SHIFT]&0x80)) { wParam = VK_EXECUTE; @@ -1835,7 +1949,7 @@ static WPARAM compose_key = 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 ) + || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state ) { if ((HIWORD(lParam)&KF_EXTENDED) == 0) { @@ -1890,6 +2004,11 @@ static WPARAM compose_key = 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,9 +2029,9 @@ static WPARAM compose_key = 0; 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)) 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; @@ -1930,9 +2049,17 @@ static WPARAM compose_key = 0; 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 +2158,18 @@ static WPARAM compose_key = 0; 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)) { @@ -2072,6 +2205,16 @@ static WPARAM compose_key = 0; return p - output; } } + + /* + * Finally, deal with Return ourselves. (Win95 seems to + * foul it up when Alt is pressed, for some reason.) + */ + if (wParam == VK_RETURN) /* Return */ + { + *p++ = 0x0D; + return p-output; + } } /* Okay we've done everything interesting; let windows deal with @@ -2102,7 +2245,7 @@ static WPARAM compose_key = 0; if ((nc=check_compose(compose_char,ch)) == -1) { - c_write1('\007'); + MessageBeep(MB_ICONHAND); return 0; } *p++ = xlat_kbd2tty((unsigned char)nc); @@ -2130,10 +2273,9 @@ static WPARAM compose_key = 0; } /* This stops ALT press-release doing a 'COMMAND MENU' function */ - if (message == WM_SYSKEYUP && wParam == VK_MENU) - { - keystate[VK_MENU] = 0; - return 0; + if (!cfg.alt_only) { + if (message == WM_SYSKEYUP && wParam == VK_MENU) + return 0; } return -1; @@ -2242,7 +2384,7 @@ void palette_reset (void) { } } -void write_clip (void *data, int len) { +void write_clip (void *data, int len, int must_deselect) { HGLOBAL clipdata; void *lock; @@ -2256,14 +2398,18 @@ void write_clip (void *data, int len) { ((unsigned char *) lock) [len] = 0; GlobalUnlock (clipdata); - SendMessage (hwnd, WM_IGNORE_CLIP, TRUE, 0); + if (!must_deselect) + SendMessage (hwnd, WM_IGNORE_CLIP, TRUE, 0); + if (OpenClipboard (hwnd)) { EmptyClipboard(); SetClipboardData (CF_TEXT, clipdata); CloseClipboard(); } else GlobalFree (clipdata); - SendMessage (hwnd, WM_IGNORE_CLIP, FALSE, 0); + + if (!must_deselect) + SendMessage (hwnd, WM_IGNORE_CLIP, FALSE, 0); } void get_clip (void **p, int *len) {