Exemplo n.º 1
0
/*
 * recent_keystroke - verbose version of key_playback
 */
int
recent_keystroke(int *cv, char *cs, size_t cslen)
{
    int c;

    if((c = key_playback(0)) != -1){
	*cv = c;
	snprintf(cs, cslen, "%.32s", pretty_command(c));
	return(0);
    }

    return(-1);
}
Exemplo n.º 2
0
/*----------------------------------------------------------------------
        Read a character from keyboard with timeout
 Input:  none

 Result: Returns command read via read_char
         Times out and returns a null command every so often

  Calculates the timeout for the read, and does a few other house keeping 
things.  The duration of the timeout is set in pine.c.
  ----------------------------------------------------------------------*/
UCS
read_command(char **utf8str)
{
    int tm = 0, more_freq_timeo;
    UCS ucs;
    long dtime; 
    static unsigned char utf8buf[7];
    unsigned char *newdestp;

    /*
     * timeo is the mail-check-interval. What we want to do (ignoring the
     * messages_queued part) is timeout more often than timeo but only
     * check for new mail every timeo or so seconds. The reason we want to
     * timeout more often is so that we will have a chance to catch the user
     * in an idle period where we can do a check_point(). Otherwise, with
     * a default mail-check-interval, we are almost always calling newmail
     * right after the user presses a key, making it the worst possible
     * time to do a checkpoint.
     */

    more_freq_timeo = MIN(get_input_timeout(), IDLE_TIMEOUT);
    if(more_freq_timeo == 0)
      more_freq_timeo = IDLE_TIMEOUT;

    cancel_busy_cue(-1);
    tm = (messages_queued(&dtime) > 1) ? (int)dtime : more_freq_timeo;

    if(utf8str)
      *utf8str = NULL;

    ucs = read_char(tm);
    if(ucs != NO_OP_COMMAND && ucs != NO_OP_IDLE && ucs != KEY_RESIZE)
      zero_new_mail_count();

#ifdef	BACKGROUND_POST
    /*
     * Any expired children to report on?
     */
    if(ps_global->post && ps_global->post->pid == 0){
	int   winner = 0;

	if(ps_global->post->status < 0){
	    q_status_message(SM_ORDER | SM_DING, 3, 3, "Abysmal failure!");
	}
	else{
	    (void) pine_send_status(ps_global->post->status,
				    ps_global->post->fcc, tmp_20k_buf, SIZEOF_20KBUF,
				    &winner);
	    q_status_message(SM_ORDER | (winner ? 0 : SM_DING), 3, 3,
			     tmp_20k_buf);

	}

	if(!winner)
	  q_status_message(SM_ORDER, 0, 3,
	  "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");

	if(ps_global->post->fcc)
	  fs_give((void **) &ps_global->post->fcc);

	fs_give((void **) &ps_global->post);
    }
#endif

    /*
     * The character we get from read_char() is a UCS-4 char. Or it could be a special
     * value like KEY_UP or NO_OP_IDLE or something similar. From here on out
     * we're going to operate with UTF-8 internally. This is the point where we
     * convert the UCS-4 input (actually whatever sort of input the user is typing
     * was converted to UCS-4 first) to UTF-8. It's easy in this read_command
     * case because if user types a non-ascii character as a command it's going to be
     * an error. All commands are ascii. In order to present a reasonable error
     * message we pass back the UTF-8 string to the caller.
     */
    if(ucs >= 0x80 && ucs < KEY_BASE){
	/*
	 * User typed a character that is non-ascii. Convert it to
	 * UTF-8.
	 */
	memset(utf8buf, 0, sizeof(utf8buf));
	newdestp = utf8_put(utf8buf, (unsigned long) ucs);
	if(newdestp - utf8buf > 1){	/* this should happen */
	    if(utf8str)
	      *utf8str = (char *) utf8buf;

	    dprint((9, "Read command: looks like user typed non-ascii command 0x%x %s: returning KEY_UTF8\n", ucs, pretty_command(ucs)));
	    ucs = KEY_UTF8;
	}
	else{
	    dprint((9, "Read command: looks like user typed unknown, non-ascii command 0x%x %s: returning KEY_UNKNOWN\n", ucs, pretty_command(ucs)));
	    ucs = KEY_UNKNOWN;	/* best we can do, shouldn't happen */
	}
    }
    else{
	dprint((9, "Read command returning: 0x%x %s\n", ucs, pretty_command(ucs)));
    }

    return(ucs);
}
Exemplo n.º 3
0
Arquivo: radio.c Projeto: nysan/alpine
/*----------------------------------------------------------------------
    Prompt user for a choice among alternatives

Args --  utf8prompt:    The prompt for the question/selection
         line:      The line to prompt on, if negative then relative to bottom
         esc_list:  ESC_KEY_S list of keys
         dflt:	    The selection when the <CR> is pressed (should probably
		      be one of the chars in esc_list)
         on_ctrl_C: The selection when ^C is pressed
         help_text: Text to be displayed on bottom two lines
	 flags:     Logically OR'd flags modifying our behavior to:
		RB_FLUSH_IN    - Discard any pending input chars.
		RB_ONE_TRY     - Only give one chance to answer.  Returns
				 on_ctrl_C value if not answered acceptably
				 on first try.
		RB_NO_NEWMAIL  - Quell the usual newmail check.
		RB_SEQ_SENSITIVE - The caller is sensitive to sequence number
				   changes so return on_ctrl_C if an
				   unsolicited expunge happens while we're
				   viewing a message.
		RB_RET_HELP    - Instead of the regular internal handling
				 way of handling help_text, this just causes
				 radio_buttons to return 3 when help is
				 asked for, so that the caller handles it
				 instead.
	
	 Note: If there are enough keys in the esc_list to need a second
	       screen, and there is no help, then the 13th key will be
	       put in the help position.

Result -- Returns the letter pressed. Will be one of the characters in the
          esc_list argument, or dflt, or on_ctrl_C, or SEQ_EXCEPTION.

This will pause for any new status message to be seen and then prompt the user.
The prompt will be truncated to fit on the screen. Redraw and resize are
handled along with ^Z suspension. Typing ^G will toggle the help text on and
off. Character types that are not buttons will result in a beep (unless one_try
is set).
  ----*/
int
radio_buttons(char *utf8prompt, int line, ESCKEY_S *esc_list, int dflt,
	      int on_ctrl_C, HelpType help_text, int flags)
{
    UCS              ucs;
    register int     ch, real_line;
    char            *q, *ds = NULL;
    unsigned         maxcol;
    int              max_label, i, start, fkey_table[12];
    int		     km_popped = 0;
    struct key	     rb_keys[12];
    struct key_menu  rb_keymenu;
    bitmap_t	     bitmap;
    struct variable *vars = ps_global->vars;
    COLOR_PAIR      *lastc = NULL, *promptc = NULL;

#ifdef	_WINDOWS
    int		     cursor_shown;

    if (mswin_usedialog()){
	MDlgButton button_list[25];
	LPTSTR     free_names[25];
	LPTSTR     free_labels[25];
	int        b, i, ret;
	char     **help;

	memset(&free_names, 0, sizeof(LPTSTR) * 25);
	memset(&free_labels, 0, sizeof(LPTSTR) * 25);
	memset(&button_list, 0, sizeof (MDlgButton) * 25);
	b = 0;

	if(flags & RB_RET_HELP){
	    if(help_text != NO_HELP)
	      alpine_panic("RET_HELP and help in radio_buttons!");

	    button_list[b].ch = '?';
	    button_list[b].rval = 3;
	    button_list[b].name = TEXT("?");
	    free_labels[b] = utf8_to_lptstr(N_("Help"));
	    button_list[b].label = free_labels[b];
	    ++b;
	}

	for(i = 0; esc_list && esc_list[i].ch != -1 && i < 23; ++i){
	  if(esc_list[i].ch != -2){
	    button_list[b].ch = esc_list[i].ch;
	    button_list[b].rval = esc_list[i].rval;
	    free_names[b] = utf8_to_lptstr(esc_list[i].name);
	    button_list[b].name = free_names[b];
	    free_labels[b] = utf8_to_lptstr(esc_list[i].label);
	    button_list[b].label = free_labels[b];
	    ++b;
	  }
	}

	button_list[b].ch = -1;
	
	/* assumption here is that HelpType is char **  */
	help = help_text;

	ret = mswin_select(utf8prompt, button_list, dflt, on_ctrl_C, help, flags);
	for(i = 0; i < 25; i++){
	    if(free_names[i])
	      fs_give((void **) &free_names[i]);
	    if(free_labels[i])
	      fs_give((void **) &free_labels[i]);
	}

	return (ret);
    }

#endif /* _WINDOWS */

    suspend_busy_cue();
    flush_ordered_messages();		/* show user previous status msgs */
    mark_status_dirty();		/* clear message next display call */
    real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line;
    MoveCursor(real_line, RAD_BUT_COL);
    CleartoEOLN();

    /*---- Find widest label ----*/
    max_label = 0;
    for(i = 0; esc_list && esc_list[i].ch != -1 && i < 11; i++){
      if(esc_list[i].ch == -2) /* -2 means to skip this key and leave blank */
	continue;
      if(esc_list[i].name)
        max_label = MAX(max_label, utf8_width(esc_list[i].name));
    }

    if(ps_global->ttyo->screen_cols - max_label - 1 > 0)
      maxcol = ps_global->ttyo->screen_cols - max_label - 1;
    else
      maxcol = 0;

    /*
     * We need to be able to truncate q, so copy it in case it is
     * a readonly string.
     */
    q = cpystr(utf8prompt);

    /*---- Init structs for keymenu ----*/
    for(i = 0; i < 12; i++)
      memset((void *)&rb_keys[i], 0, sizeof(struct key));

    memset((void *)&rb_keymenu, 0, sizeof(struct key_menu));
    rb_keymenu.how_many = 1;
    rb_keymenu.keys     = rb_keys;

    /*---- Setup key menu ----*/
    start = 0;
    clrbitmap(bitmap);
    memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(int));
    if(flags & RB_RET_HELP && help_text != NO_HELP)
      alpine_panic("RET_HELP and help in radio_buttons!");

    /* if shown, always at position 0 */
    if(help_text != NO_HELP || flags & RB_RET_HELP){
	rb_keymenu.keys[0].name  = "?";
	rb_keymenu.keys[0].label = N_("Help");
	setbitn(0, bitmap);
	fkey_table[0] = ctrl('G');
	start++;
    }

    if(on_ctrl_C){
	rb_keymenu.keys[1].name  = "^C";
	rb_keymenu.keys[1].label = N_("Cancel");
	setbitn(1, bitmap);
	fkey_table[1] = ctrl('C');
	start++;
    }

    start = start ? 2 : 0;
    /*---- Show the usual possible keys ----*/
    for(i=start; esc_list && esc_list[i-start].ch != -1; i++){
	/*
	 * If we have an esc_list item we'd like to put in the non-existent
	 * 13th slot, and there is no help, we put it in the help slot
	 * instead.  We're hacking now...!
	 *
	 * We may also have invisible esc_list items that don't show up
	 * on the screen.  We use this when we have two different keys
	 * which are synonyms, like ^P and KEY_UP.  If all the slots are
	 * already full we can still fit invisible keys off the screen to
	 * the right.  A key is invisible if it's label is "".
	 */
	if(i >= 12){
	    if(esc_list[i-start].label
	       && esc_list[i-start].label[0] != '\0'){  /* visible */
		if(i == 12){  /* special case where we put it in help slot */
		    if(help_text != NO_HELP)
		  alpine_panic("Programming botch in radio_buttons(): too many keys");

		    if(esc_list[i-start].ch != -2)
		      setbitn(0, bitmap); /* the help slot */

		    fkey_table[0] = esc_list[i-start].ch;
		    rb_keymenu.keys[0].name  = esc_list[i-start].name;
		    if(esc_list[i-start].ch != -2
		       && esc_list[i-start].rval == dflt
		       && esc_list[i-start].label){
		        size_t l;

			l = strlen(esc_list[i-start].label) + 2;
			ds = (char *)fs_get((l+1) * sizeof(char));
			snprintf(ds, l+1, "[%s]", esc_list[i-start].label);
			ds[l] = '\0';
			rb_keymenu.keys[0].label = ds;
		    }
		    else
		      rb_keymenu.keys[0].label = esc_list[i-start].label;
		}
		else
		  alpine_panic("Botch in radio_buttons(): too many keys");
	    }
	}
	else{
	    if(esc_list[i-start].ch != -2)
	      setbitn(i, bitmap);

	    fkey_table[i] = esc_list[i-start].ch;
	    rb_keymenu.keys[i].name  = esc_list[i-start].name;
	    if(esc_list[i-start].ch != -2
	       && esc_list[i-start].rval == dflt
	       && esc_list[i-start].label){
	        size_t l;

		l = strlen(esc_list[i-start].label) + 2;
		ds = (char *)fs_get((l+1) * sizeof(char));
		snprintf(ds, l+1, "[%s]", esc_list[i-start].label);
		ds[l] = '\0';
		rb_keymenu.keys[i].label = ds;
	    }
	    else
	      rb_keymenu.keys[i].label = esc_list[i-start].label;
	}
    }

    for(; i < 12; i++)
      rb_keymenu.keys[i].name = NULL;

    ps_global->mangled_footer = 1;

#ifdef	_WINDOWS
    cursor_shown = mswin_showcaret(1);
#endif

    if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR &&
       VAR_PROMPT_BACK_COLOR &&
       pico_is_good_color(VAR_PROMPT_FORE_COLOR) &&
       pico_is_good_color(VAR_PROMPT_BACK_COLOR)){
	lastc = pico_get_cur_color();
	if(lastc){
	    promptc = new_color_pair(VAR_PROMPT_FORE_COLOR,
				     VAR_PROMPT_BACK_COLOR);
	    (void)pico_set_colorp(promptc, PSC_NONE);
	}
    }
    else
      StartInverse();

    draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q);

    while(1){
        fflush(stdout);

	/*---- Paint the keymenu ----*/
	if(lastc)
	  (void)pico_set_colorp(lastc, PSC_NONE);
	else
	  EndInverse();

	draw_keymenu(&rb_keymenu, bitmap, ps_global->ttyo->screen_cols,
		     1 - FOOTER_ROWS(ps_global), 0, FirstMenu);
	if(promptc)
	  (void)pico_set_colorp(promptc, PSC_NONE);
	else
	  StartInverse();

	MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1));

	if(flags & RB_FLUSH_IN)
	  flush_input();

  newcmd:
	/* Timeout 5 min to keep imap mail stream alive */
        ucs = read_char(600);
        dprint((2,
                   "Want_to read: %s (0x%x)\n", pretty_command(ucs), ucs));
	if((ucs < 0x80) && isupper((unsigned char) ucs))
	  ucs = tolower((unsigned char) ucs);

	if(F_ON(F_USE_FK,ps_global)
	   && (((ucs < 0x80) && isalpha((unsigned char) ucs) && !strchr("YyNn",(int) ucs))
	       || ((ucs >= PF1 && ucs <= PF12)
		   && (ucs = fkey_table[ucs - PF1]) == NO_OP_COMMAND))){
	    /*
	     * The funky test above does two things.  It maps
	     * esc_list character commands to function keys, *and* prevents
	     * character commands from input while in function key mode.
	     * NOTE: this breaks if we ever need more than the first
	     * twelve function keys...
	     */
	    if(flags & RB_ONE_TRY){
		ch = ucs = on_ctrl_C;
	        goto out_of_loop;
	    }

	    Writechar(BELL, 0);
	    continue;
	}

        switch(ucs){

          default:
	    for(i = 0; esc_list && esc_list[i].ch != -1; i++)
	      if(ucs == esc_list[i].ch){
		  int len, n;

		  MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1));
		  for(n = 0, len = ps_global->ttyo->screen_cols - len;
		      esc_list[i].label && esc_list[i].label[n] && len > 0;
		      n++, len--)
		    Writechar(esc_list[i].label[n], 0);

		  ch = esc_list[i].rval;
		  goto out_of_loop;
	      }

	    if(flags & RB_ONE_TRY){
		ch = on_ctrl_C;
	        goto out_of_loop;
	    }

	    Writechar(BELL, 0);
	    break;

          case ctrl('M'):
          case ctrl('J'):
            ch = dflt;
	    for(i = 0; esc_list && esc_list[i].ch != -1; i++)
	      if(ch == esc_list[i].rval){
		  int len, n;

		  MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1));
		  for(n = 0, len = ps_global->ttyo->screen_cols - len;
		      esc_list[i].label && esc_list[i].label[n] && len > 0;
		      n++, len--)
		    Writechar(esc_list[i].label[n], 0);
		  break;
	      }

            goto out_of_loop;

          case ctrl('C'):
	    if(on_ctrl_C || (flags & RB_ONE_TRY)){
		ch = on_ctrl_C;
		goto out_of_loop;
	    }

	    Writechar(BELL, 0);
	    break;


          case '?':
          case ctrl('G'):
	    if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){
		km_popped++;
		FOOTER_ROWS(ps_global) = 3;
		line = -3;
		real_line = ps_global->ttyo->screen_rows + line;
		if(lastc)
		  (void)pico_set_colorp(lastc, PSC_NONE);
		else
		  EndInverse();

		clearfooter(ps_global);
		if(promptc)
		  (void)pico_set_colorp(promptc, PSC_NONE);
		else
		  StartInverse();

		draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q);
		break;
	    }

	    if(flags & RB_RET_HELP){
		ch = 3;
		goto out_of_loop;
	    }
	    else if(help_text != NO_HELP && FOOTER_ROWS(ps_global) > 1){
		mark_keymenu_dirty();
		if(lastc)
		  (void)pico_set_colorp(lastc, PSC_NONE);
		else
		  EndInverse();

		MoveCursor(real_line + 1, RAD_BUT_COL);
		CleartoEOLN();
		MoveCursor(real_line + 2, RAD_BUT_COL);
		CleartoEOLN();
		radio_help(real_line, RAD_BUT_COL, help_text);
		sleep(5);
		MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1));
		if(promptc)
		  (void)pico_set_colorp(promptc, PSC_NONE);
		else
		  StartInverse();
	    }
	    else
	      Writechar(BELL, 0);

            break;
            

          case NO_OP_COMMAND:
	    goto newcmd;		/* misunderstood escape? */

          case NO_OP_IDLE:		/* UNODIR, keep the stream alive */
	    if(flags & RB_NO_NEWMAIL)
	      goto newcmd;

	    i = new_mail(0, VeryBadTime, NM_DEFER_SORT);
	    if(sp_expunge_count(ps_global->mail_stream)
	       && flags & RB_SEQ_SENSITIVE){
		if(on_ctrl_C)
		  ch = on_ctrl_C;
		else
		  ch = SEQ_EXCEPTION;

		goto out_of_loop;
	    }

	    if(i < 0)
	      break;		/* no changes, get on with life */
            /* Else fall into redraw to adjust displayed numbers and such */


          case KEY_RESIZE:
          case ctrl('L'):
            real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line;
	    if(lastc)
	      (void)pico_set_colorp(lastc, PSC_NONE);
	    else
	      EndInverse();

            ClearScreen();
            redraw_titlebar();
            if(ps_global->redrawer != NULL)
              (*ps_global->redrawer)();
	    if(FOOTER_ROWS(ps_global) == 3 || km_popped)
              redraw_keymenu();

	    if(ps_global->ttyo->screen_cols - max_label - 1 > 0)
	      maxcol = ps_global->ttyo->screen_cols - max_label - 1;
	    else
	      maxcol = 0;

	    if(promptc)
	      (void)pico_set_colorp(promptc, PSC_NONE);
	    else
	      StartInverse();

	    draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q);
            break;

        } /* switch */
    }

  out_of_loop:

#ifdef	_WINDOWS
    if(!cursor_shown)
      mswin_showcaret(0);
#endif

    fs_give((void **) &q);
    if(ds)
      fs_give((void **) &ds);

    if(lastc){
	(void) pico_set_colorp(lastc, PSC_NONE);
	free_color_pair(&lastc);
	if(promptc)
	  free_color_pair(&promptc);
    }
    else
      EndInverse();

    fflush(stdout);
    resume_busy_cue(0);
    if(km_popped){
	FOOTER_ROWS(ps_global) = 1;
	clearfooter(ps_global);
	ps_global->mangled_body = 1;
    }

    return(ch);
}
Exemplo n.º 4
0
/*----------------------------------------------------------------------
  Read input characters with lots of processing for arrow keys and such  (UNIX)

 Args:  time_out -- The timeout to for the reads 

 Result: returns the character read. Possible special chars.

    This deals with function and arrow keys as well. 

  The idea is that this routine handles all escape codes so it done in
  only one place. Especially so the back arrow key can work when entering
  things on a line. Also so all function keys can be disabled and not
  cause weird things to happen.
  ---*/
UCS
read_char(int time_out)
{
    UCS status, cc, ch;
    int (*key_rec)(int);

    key_rec = key_recorder;
    if(ps_global->conceal_sensitive_debugging)
      key_rec = NULL;

    /* Get input from initial-keystrokes */
    if(process_config_input(&cc)){
	ch = cc;
	return(ch);
    }

    if((ch = check_for_timeout(time_out)) != READY_TO_READ)
      goto done;
    
    switch(status = kbseq(pine_simple_ttgetc, key_rec, read_bail,
			  ps_global->input_cs, &ch)){
      case KEY_DOUBLE_ESC:
	/*
	 * Special hack to get around comm devices eating control characters.
	 */
	if(check_for_timeout(5) != READY_TO_READ){
	    dprint((9, "Read char: incomplete double escape timed out...\n"));
	    ch = KEY_JUNK;		/* user typed ESC ESC, then stopped */
	    goto done;
	}
	else
	  ch = READ_A_CHAR();

	ch &= 0x7f;

	/* We allow a 3-digit number between 001 and 255 */
	if(isdigit((unsigned char) ch)){
	    int n = 0, i = ch - '0';

	    if(i < 0 || i > 2){
		dprint((9, "Read char: double escape followed by 1st digit not 0, 1, or 2... (%d)\n", i));
		ch = KEY_JUNK;
		goto done;		/* bogus literal char value */
	    }

	    while(n++ < 2){
		if(check_for_timeout(5) != READY_TO_READ
		   || (!isdigit((unsigned char) (ch = READ_A_CHAR()))
		       || (n == 1 && i == 2 && ch > '5')
		       || (n == 2 && i == 25 && ch > '5'))){
		    dprint((9, "Read char: bad double escape, either timed out or too large 3-digit num...\n"));
		    ch = KEY_JUNK;	/* user typed ESC ESC #, stopped */
		    goto done;
		}

		i = (i * 10) + (ch - '0');
	    }

	    ch = i;
	}
	else{	/* or, normal case, ESC ESC c  means ^c */
	    if(islower((unsigned char) ch))	/* canonicalize if alpha */
	      ch = toupper((unsigned char) ch);

	    ch = (isalpha((unsigned char)ch) || ch == '@'
		  || (ch >= '[' && ch <= '_'))
		   ? ctrl(ch) : ((ch == SPACE) ? ctrl('@'): ch);
	    dprint((9, "Read char: this is a successful double escape...\n"));
	}

	goto done;

#ifdef MOUSE
      case KEY_XTERM_MOUSE:
	if(mouseexist()){
	    /*
	     * Special hack to get mouse events from an xterm.
	     * Get the details, then pass it past the keymenu event
	     * handler, and then to the installed handler if there
	     * is one...
	     */
	    static int    down = 0;
	    int           x, y, button;
	    unsigned long cmd;

	    clear_cursor_pos();
	    button = READ_A_CHAR() & 0x03;

	    x = READ_A_CHAR() - '!';
	    y = READ_A_CHAR() - '!';

	    ch = NO_OP_COMMAND;
	    if(button == 0){		/* xterm button 1 down */
		down = 1;
		if(checkmouse(&cmd, 1, x, y))
		  ch = cmd;
	    }
	    else if (down && button == 3){
		down = 0;
		if(checkmouse(&cmd, 0, x, y))
		  ch = cmd;
	    }

	    goto done;
	}

	break;
#endif /* MOUSE */

      case  KEY_UP	:
      case  KEY_DOWN	:
      case  KEY_RIGHT	:
      case  KEY_LEFT	:
      case  KEY_PGUP	:
      case  KEY_PGDN	:
      case  KEY_HOME	:
      case  KEY_END	:
      case  KEY_DEL	:
      case  PF1		:
      case  PF2		:
      case  PF3		:
      case  PF4		:
      case  PF5		:
      case  PF6		:
      case  PF7		:
      case  PF8		:
      case  PF9		:
      case  PF10	:
      case  PF11	:
      case  PF12	:
        dprint((9, "Read char returning: 0x%x %s\n", status, pretty_command(status)));
	return(status);

      case  CTRL_KEY_UP	:
	status = KEY_UP;
        dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_UP)\n", status, pretty_command(status)));
	return(status);

      case  CTRL_KEY_DOWN	:
	status = KEY_DOWN;
        dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_DOWN)\n", status, pretty_command(status)));
	return(status);

      case  CTRL_KEY_RIGHT	:
	status = KEY_RIGHT;
        dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_RIGHT)\n", status, pretty_command(status)));
	return(status);

      case  CTRL_KEY_LEFT	:
	status = KEY_LEFT;
        dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_LEFT)\n", status, pretty_command(status)));
	return(status);

      case KEY_SWALLOW_Z:
	status = KEY_JUNK;
      case KEY_SWAL_UP:
      case KEY_SWAL_DOWN:
      case KEY_SWAL_LEFT:
      case KEY_SWAL_RIGHT:
	do
	  if(check_for_timeout(2) != READY_TO_READ){
	      status = KEY_JUNK;
	      break;
	  }
	while(!strchr("~qz", READ_A_CHAR()));
	ch = (status == KEY_JUNK) ? status : status - (KEY_SWAL_UP - KEY_UP);
	goto done;

      case KEY_KERMIT:
	do{
	    cc = ch;
	    if(check_for_timeout(2) != READY_TO_READ){
		status = KEY_JUNK;
		break;
	    }
	    else
	      ch = READ_A_CHAR();
	}while(cc != '\033' && ch != '\\');

	ch = KEY_JUNK;
	goto done;

      case BADESC:
	ch = KEY_JUNK;
	goto done;

      case 0: 	/* regular character */
      default:
	/*
	 * we used to strip (ch &= 0x7f;), but this seems much cleaner
	 * in the face of line noise and has the benefit of making it
	 * tougher to emit mistakenly labeled MIME...
	 */
	if((ch & ~0x7f)
	   && ((!ps_global->keyboard_charmap || !strucmp(ps_global->keyboard_charmap, "US-ASCII"))
	       && (!ps_global->display_charmap || !strucmp(ps_global->display_charmap, "US-ASCII")))){
	    dprint((9, "Read char sees ch = 0x%x status=0x%x, returns KEY_JUNK\n", ch, status));
	    return(KEY_JUNK);
	}
	else if(ch == ctrl('Z')){
	    dprint((9, "Read char got ^Z, calling do_suspend\n"));
	    ch = do_suspend();
	    dprint((9, "After do_suspend Read char returns 0x%x %s\n", ch, pretty_command(ch)));
	    return(ch);
	}
#ifdef MOUSE
	else if(ch == ctrl('\\')){
	    int e;

	    dprint((9, "Read char got ^\\, toggle xterm mouse\n"));
	    if(F_ON(F_ENABLE_MOUSE, ps_global)){
		(e=mouseexist()) ? end_mouse() : (void) init_mouse();
		if(e != mouseexist())
		  q_status_message1(SM_ASYNC, 0, 2, "Xterm mouse tracking %s!",
						     mouseexist() ? "on" : "off");
		else if(!e)
		  q_status_message1(SM_ASYNC, 0, 2, "See help for feature \"%s\" ($DISPLAY variable set?)", pretty_feature_name(feature_list_name(F_ENABLE_MOUSE), -1));
	    }
	    else
	      q_status_message1(SM_ASYNC, 0, 2, "Feature \"%s\" not enabled",
				pretty_feature_name(feature_list_name(F_ENABLE_MOUSE), -1));

	    return(NO_OP_COMMAND);
	}
#endif /* MOUSE */


      done:
#ifdef	DEBUG
	if(ps_global->conceal_sensitive_debugging && debug < 10){
	    dprint((9, "Read char returning: <hidden char>\n"));
	}
	else{
	    dprint((9, "Read char returning: 0x%x %s\n", ch, pretty_command(ch)));
	}
#endif

        return(ch);
    }

    /* not reachable */
    return(KEY_JUNK);
}