if (left_alt && (keystate[VK_CONTROL]&0x80)) keystate[VK_MENU] = 0;
if (left_alt && (keystate[VK_CONTROL]&0x80)) { if (cfg.ctrlaltkeys) keystate[VK_MENU] = 0; else { keystate[VK_RMENU] = 0x80; left_alt = 0; } }
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_state = 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       {  /* 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];	}	/* 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;	}	/* 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 */    if (left_alt && (keystate[VK_CONTROL]&0x80))	keystate[VK_MENU] = 0;    scan = (HIWORD(lParam) & (KF_UP | KF_EXTENDED | 0xFF));    shift_state = ((keystate[VK_SHIFT]&0x80)!=0)                + ((keystate[VK_CONTROL]&0x80)!=0)*2;    /*      * 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_mouse (MB_PASTE, MA_CLICK, 0, 0);            term_mouse (MB_PASTE, MA_RELEASE, 0, 0);            return 0;        }	if (left_alt && wParam == VK_F4 && cfg.alt_f4) {            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) {	   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);	    return p-output;	}	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; return p - output;	}	/* 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;	  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 (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 if (app_cursor_keys && !cfg.no_applic_c)		    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;	    return p-output;	}    }    /* Okay we've done everything interesting; let windows deal with      * the boring stuff */    {	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 = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout);	if(r>0)	{	    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;		    }		    *p++ = xlat_kbd2tty((unsigned char)nc);		    return p-output;		}		compose_state = 0;		if( left_alt && key_down ) *p++ = '\033';		if (!key_down)		    *p++ = ch;		else		{		    if(capsOn)			ch = xlat_latkbd2win(ch);	            *p++ = xlat_kbd2tty(ch);		}	    }	    /* This is so the ALT-Numpad and dead keys work correctly. */	    keys[0] = 0;	    return p-output;	}    }    /* 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;}