fprintf(stderr, " %04x", text[i]);
fprintf(stderr, " %04x", (unsigned)text[i]);
void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen,	      unsigned int modifiers, unsigned int flags){    char output[10];    char *p = output;    int prependesc = FALSE;#if 0    int i;    fprintf(stderr, "keysym = %d, %d chars:", keysym, tlen);    for (i = 0; i < tlen; i++)	fprintf(stderr, " %04x", text[i]);    fprintf(stderr, "\n");#endif    /* XXX Num Lock */    if ((flags & PKF_REPEAT) && term->repeat_off)	return;    /* Currently, Meta always just prefixes everything with ESC. */    if (modifiers & PKM_META)	prependesc = TRUE;    modifiers &= ~PKM_META;    /*     * Alt is only used for Alt+keypad, which isn't supported yet, so     * ignore it.     */    modifiers &= ~PKM_ALT;    /* Standard local function keys */    switch (modifiers & (PKM_SHIFT | PKM_CONTROL)) {      case PKM_SHIFT:	if (keysym == PK_PAGEUP)	    /* scroll up one page */;	if (keysym == PK_PAGEDOWN)	    /* scroll down on page */;	if (keysym == PK_INSERT)	    term_do_paste(term);	break;      case PKM_CONTROL:	if (keysym == PK_PAGEUP)	    /* scroll up one line */;	if (keysym == PK_PAGEDOWN)	    /* scroll down one line */;	/* Control-Numlock for app-keypad mode switch */	if (keysym == PK_PF1)	    term->app_keypad_keys ^= 1;	break;    }    if (modifiers & PKM_ALT) {	/* Alt+F4 (close) */	/* Alt+Return (full screen) */	/* Alt+Space (system menu) */    }    if (keysym == PK_NULL && (modifiers & PKM_CONTROL) && tlen == 1 &&	text[0] >= 0x20 && text[0] <= 0x7e) {	/* ASCII chars + Control */	if (text[0] >= 0x40 && text[0] <= 0x5f ||	    text[0] >= 0x61 && text[0] <= 0x7a)	    text[0] &= 0x1f;	else {	    /*	     * Control-2 should return ^@ (0x00), Control-6 should return	     * ^^ (0x1E), and Control-Minus should return ^_ (0x1F). Since	     * the DOS keyboard handling did it, and we have nothing better	     * to do with the key combo in question, we'll also map	     * Control-Backquote to ^\ (0x1C).	     */	    switch (text[0]) {	      case ' ': text[0] = 0x00; break;	      case '-': text[0] = 0x1f; break;	      case '/': text[0] = 0x1f; break;	      case '2': text[0] = 0x00; break;	      case '3': text[0] = 0x1b; break;	      case '4': text[0] = 0x1c; break;	      case '5': text[0] = 0x1d; break;	      case '6': text[0] = 0x1e; break;	      case '7': text[0] = 0x1f; break;	      case '8': text[0] = 0x7f; break;	      case '`': text[0] = 0x1c; break;	    }	}    }    /* Nethack keypad */    if (term->cfg.nethack_keypad) {	char c = 0;	switch (keysym) {	  case PK_KP1: c = 'b'; break;	  case PK_KP2: c = 'j'; break;	  case PK_KP3: c = 'n'; break;	  case PK_KP4: c = 'h'; break;	  case PK_KP5: c = '.'; break;	  case PK_KP6: c = 'l'; break;	  case PK_KP7: c = 'y'; break;	  case PK_KP8: c = 'k'; break;	  case PK_KP9: c = 'u'; break;	}	if (c != 0) {	    if (c != '.') {		if (modifiers & PKM_CONTROL)		    c &= 0x1f;		else if (modifiers & PKM_SHIFT)		    c = toupper(c);	    }	    *p++ = c;	    goto done;	}    }    /* Numeric Keypad */    if (PK_ISKEYPAD(keysym)) {	int xkey = 0;	/*	 * In VT400 mode, PFn always emits an escape sequence.  In	 * Linux and tilde modes, this only happens in app keypad mode.	 */	if (term->cfg.funky_type == FUNKY_VT400 ||	    ((term->cfg.funky_type == FUNKY_LINUX ||	      term->cfg.funky_type == FUNKY_TILDE) &&	     term->app_keypad_keys && !term->cfg.no_applic_k)) {	    switch (keysym) {	      case PK_PF1: xkey = 'P'; break;	      case PK_PF2: xkey = 'Q'; break;	      case PK_PF3: xkey = 'R'; break;	      case PK_PF4: xkey = 'S'; break;	    }	}	if (term->app_keypad_keys && !term->cfg.no_applic_k) {	    switch (keysym) {	      case PK_KP0: xkey = 'p'; break;	      case PK_KP1: xkey = 'q'; break;	      case PK_KP2: xkey = 'r'; break;	      case PK_KP3: xkey = 's'; break;	      case PK_KP4: xkey = 't'; break;	      case PK_KP5: xkey = 'u'; break;	      case PK_KP6: xkey = 'v'; break;	      case PK_KP7: xkey = 'w'; break;	      case PK_KP8: xkey = 'x'; break;	      case PK_KP9: xkey = 'y'; break;	      case PK_KPDECIMAL: xkey = 'n'; break;	      case PK_KPENTER: xkey = 'M'; break;	    }	    if (term->cfg.funky_type == FUNKY_XTERM && tlen > 0) {		/*		 * xterm can't see the layout of the keypad, so it has		 * to rely on the X keysyms returned by the keys.		 * Hence, we look at the strings here, not the PuTTY		 * keysyms (which describe the layout).		 */		switch (text[0]) {		  case '+':		    if (modifiers & PKM_SHIFT)			xkey = 'l';		    else			xkey = 'k';		    break;		  case '/': xkey = 'o'; break;		  case '*': xkey = 'j'; break;		  case '-': xkey = 'm'; break;		}	    } else {		/*		 * In all other modes, we try to retain the layout of		 * the DEC keypad in application mode.		 */		switch (keysym) {		  case PK_KPBIGPLUS:		    /* This key covers the '-' and ',' keys on a VT220 */		    if (modifiers & PKM_SHIFT)			xkey = 'm'; /* VT220 '-' */		    else			xkey = 'l'; /* VT220 ',' */		    break;		  case PK_KPMINUS: xkey = 'm'; break;		  case PK_KPCOMMA: xkey = 'l'; break;		}	    }	}	if (xkey) {	    if (term->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);	    goto done;	}	/* Not in application mode -- treat the number pad as arrow keys? */	if ((flags & PKF_NUMLOCK) == 0) {	    switch (keysym) {	      case PK_KP0: keysym = PK_INSERT; break;	      case PK_KP1: keysym = PK_END; break;	      case PK_KP2: keysym = PK_DOWN; break;	      case PK_KP3: keysym = PK_PAGEDOWN; break;	      case PK_KP4: keysym = PK_LEFT; break;	      case PK_KP5: keysym = PK_REST; break;	      case PK_KP6: keysym = PK_RIGHT; break;	      case PK_KP7: keysym = PK_HOME; break;	      case PK_KP8: keysym = PK_UP; break;	      case PK_KP9: keysym = PK_PAGEUP; break;	    }	}    }    /* Miscellaneous keys */    switch (keysym) {      case PK_ESCAPE:	*p++ = 0x1b;	goto done;      case PK_BACKSPACE:	    if (modifiers == 0)		*p++ = (term->cfg.bksp_is_delete ? 0x7F : 0x08);	    else if (modifiers == PKM_SHIFT)		/* We do the opposite of what is configured */		*p++ = (term->cfg.bksp_is_delete ? 0x08 : 0x7F);	    else break;	    goto done;      case PK_TAB:	if (modifiers == 0)	    *p++ = 0x09;	else if (modifiers == PKM_SHIFT)	    *p++ = 0x1B, *p++ = '[', *p++ = 'Z';	else break;	goto done;	/* XXX window.c has ctrl+shift+space sending 0xa0 */      case PK_PAUSE:	if (modifiers == PKM_CONTROL)	    *p++ = 26;	else break;	goto done;      case PK_RETURN:      case PK_KPENTER: /* Odd keypad modes handled above */	if (modifiers == 0) {	    *p++ = 0x0d;	    if (term->cr_lf_return)		*p++ = 0x0a;	    goto done;	}    }    /* SCO function keys and editing keys */    if (term->cfg.funky_type == FUNKY_SCO) {	if (PK_ISFKEY(keysym) && keysym <= PK_F12) {	    static char const codes[] =		"MNOPQRSTUVWX" "YZabcdefghij" "klmnopqrstuv" "wxyz@[\\]^_`{";	    int index = keysym - PK_F1;	    if (modifiers & PKM_SHIFT) index += 12;	    if (modifiers & PKM_CONTROL) index += 24;	    p += sprintf((char *) p, "\x1B[%c", codes[index]);	    goto done;	}	if (PK_ISEDITING(keysym)) {	    int xkey = 0;	    switch (keysym) {	      case PK_DELETE:   *p++ = 0x7f; goto done;	      case PK_HOME:     xkey = 'H'; break;	      case PK_INSERT:   xkey = 'L'; break;	      case PK_END:      xkey = 'F'; break;	      case PK_PAGEUP:   xkey = 'I'; break;	      case PK_PAGEDOWN: xkey = 'G'; break;	    }	    p += sprintf((char *) p, "\x1B[%c", xkey);	}    }    if (PK_ISEDITING(keysym) && (modifiers & PKM_SHIFT) == 0) {	int code;	if (term->cfg.funky_type == FUNKY_XTERM) {	    /* Xterm shuffles these keys, apparently. */	    switch (keysym) {	      case PK_HOME:     keysym = PK_INSERT;   break;	      case PK_INSERT:   keysym = PK_HOME;     break;	      case PK_DELETE:   keysym = PK_END;      break;	      case PK_END:      keysym = PK_PAGEUP;   break;	      case PK_PAGEUP:   keysym = PK_DELETE;   break;	      case PK_PAGEDOWN: keysym = PK_PAGEDOWN; break;	    }	}	/* RXVT Home/End */	if (term->cfg.rxvt_homeend &&	    (keysym == PK_HOME || keysym == PK_END)) {	    p += sprintf((char *) p, keysym == PK_HOME ? "\x1B[H" : "\x1BOw");	    goto done;	}	if (term->vt52_mode) {	    int xkey;	    /*	     * A real VT52 doesn't have these, and a VT220 doesn't	     * send anything for them in VT52 mode.	     */	    switch (keysym) {	      case PK_HOME:     xkey = 'H'; break;	      case PK_INSERT:   xkey = 'L'; break;	      case PK_DELETE:   xkey = 'M'; break;	      case PK_END:      xkey = 'E'; break;	      case PK_PAGEUP:   xkey = 'I'; break;	      case PK_PAGEDOWN: xkey = 'G'; break;	    }	    p += sprintf((char *) p, "\x1B%c", xkey);	    goto done;	}	switch (keysym) {	  case PK_HOME:     code = 1; break;	  case PK_INSERT:   code = 2; break;	  case PK_DELETE:   code = 3; break;	  case PK_END:      code = 4; break;	  case PK_PAGEUP:   code = 5; break;	  case PK_PAGEDOWN: code = 6; break;	}	p += sprintf((char *) p, "\x1B[%d~", code);	goto done;    }    if (PK_ISFKEY(keysym)) {	/* Map Shift+F1-F10 to F11-F20 */	if (keysym >= PK_F1 && keysym <= PK_F10 && (modifiers & PKM_SHIFT))	    keysym += 10;	if ((term->vt52_mode || term->cfg.funky_type == FUNKY_VT100P) &&	    keysym <= PK_F14) {	    /* XXX This overrides the XTERM/VT52 mode below */	    int offt = 0;	    if (keysym >= PK_F6)  offt++;	    if (keysym >= PK_F12) offt++;	    p += sprintf((char *) p, term->vt52_mode ? "\x1B%c" : "\x1BO%c",			 'P' + keysym - PK_F1 - offt);	    goto done;	}	if (term->cfg.funky_type == FUNKY_LINUX && keysym <= PK_F5) {	    p += sprintf((char *) p, "\x1B[[%c", 'A' + keysym - PK_F1);	    goto done;	}	if (term->cfg.funky_type == FUNKY_XTERM && keysym <= PK_F4) {	    if (term->vt52_mode)		p += sprintf((char *) p, "\x1B%c", 'P' + keysym - PK_F1);	    else		p += sprintf((char *) p, "\x1BO%c", 'P' + keysym - PK_F1);	    goto done;	}	p += sprintf((char *) p, "\x1B[%d~", 11 + keysym - PK_F1);	goto done;    }    if (PK_ISCURSOR(keysym)) {	int xkey;	switch (keysym) {	  case PK_UP:    xkey = 'A'; break;	  case PK_DOWN:  xkey = 'B'; break;	  case PK_RIGHT: xkey = 'C'; break;	  case PK_LEFT:  xkey = 'D'; break;	  case PK_REST:  xkey = 'G'; break; /* centre key on number pad */	}	if (term->vt52_mode)	    p += sprintf((char *) p, "\x1B%c", xkey);	else {	    int app_flg = (term->app_cursor_keys && !term->cfg.no_applic_c);	    /* Useful mapping of Ctrl-arrows */	    if (modifiers == PKM_CONTROL)		app_flg = !app_flg;	    if (app_flg)		p += sprintf((char *) p, "\x1BO%c", xkey);	    else		p += sprintf((char *) p, "\x1B[%c", xkey);	}	goto done;    }  done:    if (p > output || tlen > 0) {	/*	 * Interrupt an ongoing paste. I'm not sure	 * this is sensible, but for the moment it's	 * preferable to having to faff about buffering	 * things.	 */	term_nopaste(term);	/*	 * 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.	 */	term_seen_key_event(term);	if (prependesc) {#if 0	    fprintf(stderr, "sending ESC\n");#endif	    ldisc_send(term->ldisc, "\x1b", 1, 1);	}	if (p > output) {#if 0	    fprintf(stderr, "sending %d bytes:", p - output);	    for (i = 0; i < p - output; i++)		fprintf(stderr, " %02x", output[i]);	    fprintf(stderr, "\n");#endif	    ldisc_send(term->ldisc, output, p - output, 1);	} else if (tlen > 0) {#if 0	    fprintf(stderr, "sending %d unichars:", tlen);	    for (i = 0; i < tlen; i++)		fprintf(stderr, " %04x", text[i]);	    fprintf(stderr, "\n");#endif	    luni_send(term->ldisc, text, tlen, 1);	}    }}