show_mouseptr(1); click (MB_SELECT, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam))); SetCapture(hwnd); return 0;
case WM_MBUTTONDOWN: case WM_RBUTTONDOWN:
static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,                                 WPARAM wParam, LPARAM lParam) {    HDC hdc;    static int ignore_size = FALSE;    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:	if (pending_netevent)	    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",		       MB_ICONWARNING | MB_OKCANCEL) == IDOK)	    DestroyWindow(hwnd);	return 0;      case WM_DESTROY:        show_mouseptr(1);	PostQuitMessage (0);	return 0;      case WM_SYSCOMMAND:	switch (wParam & ~0xF) {       /* low 4 bits reserved to Windows */	  case IDM_SHOWLOG:	    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;		if (wParam == IDM_DUPSESS) {		    /*		     * Allocate a file-mapping memory chunk for the		     * config structure.		     */		    SECURITY_ATTRIBUTES sa;		    Config *p;		    sa.nLength = sizeof(sa);		    sa.lpSecurityDescriptor = NULL;		    sa.bInheritHandle = TRUE;		    filemap = CreateFileMapping((HANDLE)0xFFFFFFFF,						&sa,						PAGE_READWRITE,						0,						sizeof(Config),						NULL);		    if (filemap) {			p = (Config *)MapViewOfFile(filemap,						    FILE_MAP_WRITE,						    0, 0, sizeof(Config));			if (p) {			    *p = cfg;  /* structure copy */			    UnmapViewOfFile(p);			}		    }		    sprintf(c, "putty &%p", filemap);		    cl = c;		} else if (wParam == IDM_SAVEDSESS) {		    char *session = sessions[(lParam - IDM_SAVED_MIN) / 16];		    cl = smalloc(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;		GetModuleFileName (NULL, b, sizeof(b)-1);		si.cb = sizeof(si);		si.lpReserved = NULL;		si.lpDesktop = NULL;		si.lpTitle = NULL;		si.dwFlags = 0;		si.cbReserved2 = 0;		si.lpReserved2 = NULL;		CreateProcess (b, cl, NULL, NULL, TRUE,			       NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);		if (filemap)		    CloseHandle(filemap);		if (freecl)		    sfree(cl);	    }	    break;          case IDM_RECONF:            {                int prev_alwaysontop = cfg.alwaysontop;                int prev_sunken_edge = cfg.sunken_edge;		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();		}                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 &= ~(WS_EX_TOPMOST);                            SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,                                         SWP_NOMOVE | SWP_NOSIZE);                        }                    }                    if (cfg.sunken_edge)                        nexflag |= WS_EX_CLIENTEDGE;                    else                        nexflag &= ~(WS_EX_CLIENTEDGE);                    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 (cfg.height != rows ||		    cfg.width != cols ||		    old_fwidth != font_width ||		    old_fheight != font_height ||		    cfg.savelines != savelines ||                    cfg.sunken_edge != prev_sunken_edge)		    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);		}                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_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;	  case IDM_TEL_EL: back->special (TS_EL); break;	  case IDM_TEL_GA: back->special (TS_GA); break;	  case IDM_TEL_NOP: back->special (TS_NOP); break;	  case IDM_TEL_ABORT: back->special (TS_ABORT); break;	  case IDM_TEL_AO: back->special (TS_AO); break;	  case IDM_TEL_IP: back->special (TS_IP); break;	  case IDM_TEL_SUSP: back->special (TS_SUSP); break;	  case IDM_TEL_EOR: back->special (TS_EOR); break;	  case IDM_TEL_EOF: back->special (TS_EOF); break;	  case IDM_ABOUT:	    showabout (hwnd);	    break;	default:	  if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {	    SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);	  }	}	break;#define X_POS(l) ((int)(short)LOWORD(l))#define Y_POS(l) ((int)(short)HIWORD(l))#define TO_CHR_X(x) (((x)<0 ? (x)-font_width+1 : (x)) / font_width)#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.	 */        noise_ultralight(lParam);	if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {	    Mouse_Button b;	    if (wParam & MK_LBUTTON)		b = MB_SELECT;	    else if (wParam & MK_MBUTTON)		b = cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND;	    else		b = cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE;	    term_mouse (b, MA_DRAG, TO_CHR_X(X_POS(lParam)),			TO_CHR_Y(Y_POS(lParam)));	}	return 0;      case WM_NCMOUSEMOVE:	show_mouseptr(1);        noise_ultralight(lParam);	return 0;      case WM_IGNORE_CLIP:	ignore_clip = wParam;	       /* don't panic on DESTROYCLIPBOARD */	break;      case WM_DESTROYCLIPBOARD:	if (!ignore_clip)	    term_deselect();	ignore_clip = FALSE;	return 0;      case WM_PAINT:	{	    PAINTSTRUCT p;            HideCaret(hwnd);	    hdc = BeginPaint (hwnd, &p);	    if (pal) {		SelectPalette (hdc, pal, TRUE);		RealizePalette (hdc);	    }	    term_paint (hdc, p.rcPaint.left, p.rcPaint.top,			p.rcPaint.right, p.rcPaint.bottom);	    SelectObject (hdc, GetStockObject(SYSTEM_FONT));	    SelectObject (hdc, GetStockObject(WHITE_PEN));	    EndPaint (hwnd, &p);            ShowCaret(hwnd);	}	return 0;      case WM_NETEVENT:	/* Notice we can get multiple netevents, FD_READ, FD_WRITE etc	 * but the only one that's likely to try to overload us is FD_READ.	 * This means buffering just one is fine.	 */	if (pending_netevent)	    enact_pending_netevent();	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, 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();	term_update();	break;      case WM_IGNORE_SIZE:	ignore_size = TRUE;	       /* don't panic on next WM_SIZE msg */	break;      case WM_ENTERSIZEMOVE:        EnableSizeTip(1);        resizing = TRUE;	need_backend_resize = FALSE;        break;      case WM_EXITSIZEMOVE:        EnableSizeTip(0);        resizing = FALSE;	if (need_backend_resize)	    back->size();        break;      case WM_SIZING:	{	    int width, height, w, h, ew, eh;	    LPRECT r = (LPRECT)lParam;	    width = r->right - r->left - extra_width;	    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) {		if (wParam == WMSZ_LEFT ||		    wParam == WMSZ_BOTTOMLEFT ||		    wParam == WMSZ_TOPLEFT)		    r->left += ew;		else		    r->right -= ew;	    }	    if (eh != 0) {		if (wParam == WMSZ_TOP ||		    wParam == WMSZ_TOPRIGHT ||		    wParam == WMSZ_TOPLEFT)		    r->top += eh;		else		    r->bottom -= eh;	    }	    if (ew || eh)		return 1;	    else		return 0;	}        /* break;  (never reached) */      case WM_SIZE:	if (wParam == SIZE_MINIMIZED) {	    SetWindowText (hwnd,			   cfg.win_name_always ? window_name : icon_name);	    break;	}	if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)	    SetWindowText (hwnd, window_name);	if (!ignore_size) {	    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);	    w = width / font_width; if (w < 1) w = 1;	    h = height / font_height; if (h < 1) h = 1;#if 0 /* we have fixed this using WM_SIZING now */	    ew = width - w * font_width;	    eh = height - h * font_height;	    if (ew != 0 || eh != 0) {		RECT r;		GetWindowRect (hwnd, &r);		SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);		SetWindowPos (hwnd, NULL, 0, 0,			      r.right - r.left - ew, r.bottom - r.top - eh,			      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);	    }#endif	    if (w != cols || h != rows || just_reconfigged) {		term_invalidate();		term_size (h, w, cfg.savelines);                /*                 * Don't call back->size in mid-resize. (To prevent                 * massive numbers of resize events getting sent                 * down the connection during an NT opaque drag.)                 */                if (!resizing)                    back->size();		else		    need_backend_resize = TRUE;		just_reconfigged = FALSE;	    }	}	ignore_size = FALSE;	return 0;      case WM_VSCROLL:	switch (LOWORD(wParam)) {	  case SB_BOTTOM: term_scroll(-1, 0); break;	  case SB_TOP: term_scroll(+1, 0); break;	  case SB_LINEDOWN: term_scroll (0, +1); break;	  case SB_LINEUP: term_scroll (0, -1); break;	  case SB_PAGEDOWN: term_scroll (0, +rows/2); break;	  case SB_PAGEUP: term_scroll (0, -rows/2); break;	  case SB_THUMBPOSITION: case SB_THUMBTRACK:	    term_scroll (1, HIWORD(wParam)); break;	}	break;      case WM_PALETTECHANGED:	if ((HWND) wParam != hwnd && pal != NULL) {	    HDC hdc = get_ctx();	    if (hdc) {		if (RealizePalette (hdc) > 0)		    UpdateColors (hdc);		free_ctx (hdc);	    }	}	break;      case WM_QUERYNEWPALETTE:	if (pal != NULL) {	    HDC hdc = get_ctx();	    if (hdc) {		if (RealizePalette (hdc) > 0)		    UpdateColors (hdc);		free_ctx (hdc);		return TRUE;	    }	}	return FALSE;      case WM_KEYDOWN:      case WM_SYSKEYDOWN:      case WM_KEYUP:      case WM_SYSKEYUP:	/*	 * Add the scan code and keypress timing to the random	 * number noise.	 */        noise_ultralight(lParam);	/*	 * We don't do TranslateMessage since it disassociates the	 * resulting CHAR message from the KEYDOWN that sparked it,	 * which we occasionally don't want. Instead, we process	 * KEYDOWN, and call the Win32 translator functions so that	 * we get the translations under _our_ control.	 */	{	    unsigned char buf[20];	    int 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:	/*	 * Nevertheless, we are prepared to deal with WM_CHAR	 * messages, should they crop up. So if someone wants to	 * post the things to us as part of a macro manoeuvre,	 * we're ready to cope.	 */	{	    char c = xlat_kbd2tty((unsigned char)wParam);	    ldisc_send (&c, 1);	}	return 0;    }    return DefWindowProc (hwnd, message, wParam, lParam);}