lpage_send(kbd_codepage, &ch, 1);
lpage_send(kbd_codepage, &ch, 1, 1);
static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,			unsigned char *output){    BYTE keystate[256];    int scan, left_alt = 0, key_down, shift_state;    int r, i, code;    unsigned char *p = output;    static int alt_sum = 0;    HKL kbd_layout = GetKeyboardLayout(0);    static WORD keys[3];    static int compose_char = 0;    static WPARAM compose_key = 0;    r = GetKeyboardState(keystate);    if (!r)	memset(keystate, 0, sizeof(keystate));    else {#if 0#define SHOW_TOASCII_RESULT	{			       /* Tell us all about key events */	    static BYTE oldstate[256];	    static int first = 1;	    static int scan;	    int ch;	    if (first)		memcpy(oldstate, keystate, sizeof(oldstate));	    first = 0;	    if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT) {		debug(("+"));	    } else if ((HIWORD(lParam) & KF_UP)		       && scan == (HIWORD(lParam) & 0xFF)) {		debug((". U"));	    } else {		debug((".\n"));		if (wParam >= 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];	}	/* Nastyness with NUMLock - Shift-NUMLock is left alone though */	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;	    /* UnToggle NUMLock */	    if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0)		keystate[VK_NUMLOCK] ^= 1;	}	/* And write back the 'adjusted' state */	SetKeyboardState(keystate);    }    /* Disable Auto repeat if required */    if (repeat_off && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT)	return 0;    if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0)	left_alt = 1;    key_down = ((HIWORD(lParam) & KF_UP) == 0);    /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */    if (left_alt && (keystate[VK_CONTROL] & 0x80)) {	if (cfg.ctrlaltkeys)	    keystate[VK_MENU] = 0;	else {	    keystate[VK_RMENU] = 0x80;	    left_alt = 0;	}    }    alt_pressed = (left_alt && key_down);    scan = (HIWORD(lParam) & (KF_UP | KF_EXTENDED | 0xFF));    shift_state = ((keystate[VK_SHIFT] & 0x80) != 0)	+ ((keystate[VK_CONTROL] & 0x80) != 0) * 2;    /* Note if AltGr was pressed and if it was used as a compose key */    if (!compose_state) {	compose_key = 0x100;	if (cfg.compose_key) {	    if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED))		compose_key = wParam;	}	if (wParam == VK_APPS)	    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;    /*      * 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;    }    /* Make sure we're not pasting */    if (key_down)	term_nopaste();    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.no_applic_k		     && cfg.funky_type != 2)	|| cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) {	if ((HIWORD(lParam) & KF_EXTENDED) == 0) {	    int nParam = 0;	    switch (wParam) {	      case VK_INSERT:		nParam = VK_NUMPAD0;		break;	      case VK_END:		nParam = VK_NUMPAD1;		break;	      case VK_DOWN:		nParam = VK_NUMPAD2;		break;	      case VK_NEXT:		nParam = VK_NUMPAD3;		break;	      case VK_LEFT:		nParam = VK_NUMPAD4;		break;	      case VK_CLEAR:		nParam = VK_NUMPAD5;		break;	      case VK_RIGHT:		nParam = VK_NUMPAD6;		break;	      case VK_HOME:		nParam = VK_NUMPAD7;		break;	      case VK_UP:		nParam = VK_NUMPAD8;		break;	      case VK_PRIOR:		nParam = VK_NUMPAD9;		break;	      case VK_DELETE:		nParam = VK_DECIMAL;		break;	    }	    if (nParam) {		if (keystate[VK_NUMLOCK] & 1)		    shift_state |= 1;		wParam = nParam;	    }	}    }    /* If a key is pressed and AltGr is not active */    if (key_down && (keystate[VK_RMENU] & 0x80) == 0 && !compose_state) {	/* Okay, prepare for most alts then ... */	if (left_alt)	    *p++ = '\033';	/* Lets see if it's a pattern we know all about ... */	if (wParam == VK_PRIOR && shift_state == 1) {	    SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);	    return 0;	}	if (wParam == VK_NEXT && shift_state == 1) {	    SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);	    return 0;	}	if (wParam == VK_INSERT && shift_state == 1) {	    term_do_paste();	    return 0;	}	if (left_alt && wParam == VK_F4 && cfg.alt_f4) {	    return -1;	}	if (left_alt && wParam == VK_SPACE && cfg.alt_space) {	    SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);	    return -1;	}	if (left_alt && wParam == VK_RETURN && cfg.fullscreenonaltenter) {	    flip_full_screen();	    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) {	    switch (wParam) {	      case VK_NUMPAD1:		*p++ = shift_state ? 'B' : 'b';		return p - output;	      case VK_NUMPAD2:		*p++ = shift_state ? 'J' : 'j';		return p - output;	      case VK_NUMPAD3:		*p++ = shift_state ? 'N' : 'n';		return p - output;	      case VK_NUMPAD4:		*p++ = shift_state ? 'H' : 'h';		return p - output;	      case VK_NUMPAD5:		*p++ = shift_state ? '.' : '.';		return p - output;	      case VK_NUMPAD6:		*p++ = shift_state ? 'L' : 'l';		return p - output;	      case VK_NUMPAD7:		*p++ = shift_state ? 'Y' : 'y';		return p - output;	      case VK_NUMPAD8:		*p++ = shift_state ? 'K' : 'k';		return p - output;	      case VK_NUMPAD9:		*p++ = shift_state ? 'U' : 'u';		return p - output;	    }	}	/* Application Keypad */	if (!left_alt) {	    int xkey = 0;	    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 && !cfg.no_applic_k)		switch (wParam) {		  case VK_NUMPAD0:		    xkey = 'p';		    break;		  case VK_NUMPAD1:		    xkey = 'q';		    break;		  case VK_NUMPAD2:		    xkey = 'r';		    break;		  case VK_NUMPAD3:		    xkey = 's';		    break;		  case VK_NUMPAD4:		    xkey = 't';		    break;		  case VK_NUMPAD5:		    xkey = 'u';		    break;		  case VK_NUMPAD6:		    xkey = 'v';		    break;		  case VK_NUMPAD7:		    xkey = 'w';		    break;		  case VK_NUMPAD8:		    xkey = 'x';		    break;		  case VK_NUMPAD9:		    xkey = 'y';		    break;		  case VK_DECIMAL:		    xkey = 'n';		    break;		  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';		    break;		}	    if (xkey) {		if (vt52_mode) {		    if (xkey >= 'P' && xkey <= 'S')			p += sprintf((char *) p, "\x1B%c", xkey);		    else			p += sprintf((char *) p, "\x1B?%c", xkey);		} else		    p += sprintf((char *) p, "\x1BO%c", xkey);		return p - output;	    }	}	if (wParam == VK_BACK && shift_state == 0) {	/* Backspace */	    *p++ = (cfg.bksp_is_delete ? 0x7F : 0x08);	    *p++ = 0;	    return -2;	}	if (wParam == VK_TAB && shift_state == 1) {	/* Shift tab */	    *p++ = 0x1B;	    *p++ = '[';	    *p++ = 'Z';	    return p - output;	}	if (wParam == VK_SPACE && shift_state == 2) {	/* Ctrl-Space */	    *p++ = 0;	    return p - output;	}	if (wParam == VK_SPACE && shift_state == 3) {	/* Ctrl-Shift-Space */	    *p++ = 160;	    return p - output;	}	if (wParam == VK_CANCEL && shift_state == 2) {	/* Ctrl-Break */	    *p++ = 3;	    *p++ = 0;	    return -2;	}	if (wParam == VK_PAUSE) {      /* Break/Pause */	    *p++ = 26;	    *p++ = 0;	    return -2;	}	/* Control-2 to Control-8 are special */	if (shift_state == 2 && wParam >= '2' && wParam <= '8') {	    *p++ = "\000\033\034\035\036\037\177"[wParam - '2'];	    return p - output;	}	if (shift_state == 2 && wParam == 0xBD) {	    *p++ = 0x1F;	    return p - output;	}	if (shift_state == 2 && wParam == 0xDF) {	    *p++ = 0x1C;	    return p - output;	}	if (shift_state == 0 && wParam == VK_RETURN && cr_lf_return) {	    *p++ = '\r';	    *p++ = '\n';	    return p - output;	}	/*	 * Next, all the keys that do tilde codes. (ESC '[' nn '~',	 * for integer decimal nn.)	 *	 * We also deal with the weird ones here. Linux VCs replace F1	 * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but	 * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w	 * respectively.	 */	code = 0;	switch (wParam) {	  case VK_F1:	    code = (keystate[VK_SHIFT] & 0x80 ? 23 : 11);	    break;	  case VK_F2:	    code = (keystate[VK_SHIFT] & 0x80 ? 24 : 12);	    break;	  case VK_F3:	    code = (keystate[VK_SHIFT] & 0x80 ? 25 : 13);	    break;	  case VK_F4:	    code = (keystate[VK_SHIFT] & 0x80 ? 26 : 14);	    break;	  case VK_F5:	    code = (keystate[VK_SHIFT] & 0x80 ? 28 : 15);	    break;	  case VK_F6:	    code = (keystate[VK_SHIFT] & 0x80 ? 29 : 17);	    break;	  case VK_F7:	    code = (keystate[VK_SHIFT] & 0x80 ? 31 : 18);	    break;	  case VK_F8:	    code = (keystate[VK_SHIFT] & 0x80 ? 32 : 19);	    break;	  case VK_F9:	    code = (keystate[VK_SHIFT] & 0x80 ? 33 : 20);	    break;	  case VK_F10:	    code = (keystate[VK_SHIFT] & 0x80 ? 34 : 21);	    break;	  case VK_F11:	    code = 23;	    break;	  case VK_F12:	    code = 24;	    break;	  case VK_F13:	    code = 25;	    break;	  case VK_F14:	    code = 26;	    break;	  case VK_F15:	    code = 28;	    break;	  case VK_F16:	    code = 29;	    break;	  case VK_F17:	    code = 31;	    break;	  case VK_F18:	    code = 32;	    break;	  case VK_F19:	    code = 33;	    break;	  case VK_F20:	    code = 34;	    break;	}	if ((shift_state&2) == 0) switch (wParam) {	  case VK_HOME:	    code = 1;	    break;	  case VK_INSERT:	    code = 2;	    break;	  case VK_DELETE:	    code = 3;	    break;	  case VK_END:	    code = 4;	    break;	  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 (vt52_mode && code > 0 && code <= 6) {	    p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]);	    return p - output;	}	if (cfg.funky_type == 5 &&     /* SCO function keys */	    code >= 11 && code <= 34) {	    char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";	    int index = 0;	    switch (wParam) {	      case VK_F1: index = 0; break;	      case VK_F2: index = 1; break;	      case VK_F3: index = 2; break;	      case VK_F4: index = 3; break;	      case VK_F5: index = 4; break;	      case VK_F6: index = 5; break;	      case VK_F7: index = 6; break;	      case VK_F8: index = 7; break;	      case VK_F9: index = 8; break;	      case VK_F10: index = 9; break;	      case VK_F11: index = 10; break;	      case VK_F12: index = 11; break;	    }	    if (keystate[VK_SHIFT] & 0x80) index += 12;	    if (keystate[VK_CONTROL] & 0x80) index += 24;	    p += sprintf((char *) p, "\x1B[%c", codes[index]);	    return p - output;	}	if (cfg.funky_type == 5 &&     /* SCO small keypad */	    code >= 1 && code <= 6) {	    char codes[] = "HL.FIG";	    if (code == 3) {		*p++ = '\x7F';	    } else {		p += sprintf((char *) p, "\x1B[%c", codes[code-1]);	    }	    return p - output;	}	if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {	    int offt = 0;	    if (code > 15)		offt++;	    if (code > 21)		offt++;	    if (vt52_mode)		p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt);	    else		p +=		    sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt);	    return p - output;	}	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) {	    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)) {	    p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw");	    return p - output;	}	if (code) {	    p += sprintf((char *) p, "\x1B[%d~", code);	    return p - output;	}	/*	 * Now the remaining keys (arrows and Keypad 5. Keypad 5 for	 * some reason seems to send VK_CLEAR to Windows...).	 */	{	    char xkey = 0;	    switch (wParam) {	      case VK_UP:		xkey = 'A';		break;	      case VK_DOWN:		xkey = 'B';		break;	      case VK_RIGHT:		xkey = 'C';		break;	      case VK_LEFT:		xkey = 'D';		break;	      case VK_CLEAR:		xkey = 'G';		break;	    }	    if (xkey) {		if (vt52_mode)		    p += sprintf((char *) p, "\x1B%c", xkey);		else {		    int app_flg = (app_cursor_keys && !cfg.no_applic_c);		    /* VT100 & VT102 manuals both state the app cursor keys		     * only work if the app keypad is on.		     */		    if (!app_keypad_keys)			app_flg = 0;		    /* Useful mapping of Ctrl-arrows */		    if (shift_state == 2)			app_flg = !app_flg;		    if (app_flg)			p += sprintf((char *) p, "\x1BO%c", xkey);		    else			p += sprintf((char *) p, "\x1B[%c", xkey);		}		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;	    *p++ = 0;	    return -2;	}	if (left_alt && wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9)	    alt_sum = alt_sum * 10 + wParam - VK_NUMPAD0;	else	    alt_sum = 0;    }    /* Okay we've done everything interesting; let windows deal with      * the boring stuff */    {	BOOL capsOn=0;	/* helg: clear CAPS LOCK state if caps lock switches to cyrillic */	if(cfg.xlat_capslockcyr && keystate[VK_CAPITAL] != 0) {	    capsOn= !left_alt;	    keystate[VK_CAPITAL] = 0;	}	r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout);#ifdef SHOW_TOASCII_RESULT	if (r == 1 && !key_down) {	    if (alt_sum) {		if (in_utf || dbcs_screenfont)		    debug((", (U+%04x)", alt_sum));		else		    debug((", LCH(%d)", alt_sum));	    } else {		debug((", ACH(%d)", keys[0]));	    }	} else if (r > 0) {	    int r1;	    debug((", ASC("));	    for (r1 = 0; r1 < r; r1++) {		debug(("%s%d", r1 ? "," : "", keys[r1]));	    }	    debug((")"));	}#endif	if (r > 0) {	    WCHAR keybuf;	    p = output;	    for (i = 0; i < r; i++) {		unsigned char ch = (unsigned char) keys[i];		if (compose_state == 2 && (ch & 0x80) == 0 && ch > ' ') {		    compose_char = ch;		    compose_state++;		    continue;		}		if (compose_state == 3 && (ch & 0x80) == 0 && ch > ' ') {		    int nc;		    compose_state = 0;		    if ((nc = check_compose(compose_char, ch)) == -1) {			MessageBeep(MB_ICONHAND);			return 0;		    }		    keybuf = nc;		    luni_send(&keybuf, 1);		    continue;		}		compose_state = 0;		if (!key_down) {		    if (alt_sum) {			if (in_utf || dbcs_screenfont) {			    keybuf = alt_sum;			    luni_send(&keybuf, 1);			} else {			    ch = (char) alt_sum;			    /*			     * We need not bother about stdin			     * backlogs here, because in GUI PuTTY			     * we can't do anything about it			     * anyway; there's no means of asking			     * Windows to hold off on KEYDOWN			     * messages. We _have_ to buffer			     * everything we're sent.			     */			    ldisc_send(&ch, 1);			}			alt_sum = 0;		    } else			lpage_send(kbd_codepage, &ch, 1);		} else {		    if(capsOn && ch < 0x80) {			WCHAR cbuf[2];			cbuf[0] = 27;			cbuf[1] = xlat_uskbd2cyrllic(ch);			luni_send(cbuf+!left_alt, 1+!!left_alt);		    } else {			char cbuf[2];			cbuf[0] = '\033';			cbuf[1] = ch;			lpage_send(kbd_codepage, cbuf+!left_alt, 1+!!left_alt);		    }		}		show_mouseptr(0);	    }	    /* This is so the ALT-Numpad and dead keys work correctly. */	    keys[0] = 0;	    return p - output;	}	/* If we're definitly not building up an ALT-54321 then clear it */	if (!left_alt)	    keys[0] = 0;	/* If we will be using alt_sum fix the 256s */	else if (keys[0] && (in_utf || dbcs_screenfont))	    keys[0] = 10;    }    /*     * ALT alone may or may not want to bring up the System menu.     * If it's not meant to, we return 0 on presses or releases of     * ALT, to show that we've swallowed the keystroke. Otherwise     * we return -1, which means Windows will give the keystroke     * its default handling (i.e. bring up the System menu).     */    if (wParam == VK_MENU && !cfg.alt_only)	return 0;    return -1;}