[comp.sources.misc] JOVE support for VT200-type function keys

jimp@cognos.UUCP (Jim Patterson) (07/04/87)

I've put together a series of differences we've applied to JOVE
since we got it from USENET.  Basically these changes fall into
two categories:

  Support for ANSI function keys (VT200-style).  The existing support
wasn't able to handle function keys with numeric parameters.  This is
now possible, though not quite as general as the rest of the
key-mapping.  Incidently, Dasher terminals that have an ANSI mode and
SUN workstations can make use of the same logic.

To enable the ANSI function key support, you need to bind the ANSI
function code initiator to the function ansi-codes.  This is a special
prefix which existed in the original version of jove that we got
(4.6.1.4), but which we have extended somewhat.  The following bindings
work for most ANSI-style terminals

	bind-to-key ansi-codes ^[[
	bind-to-key ansi-codes ^[O

If you are running a terminal which transmits 8-bit controls, then set the
environment variable METAKEY and define the following bindings instead.

	bind-to-key ansi-codes ^[^[
	bind-to-key ansi-codes ^[^O

  We have included a few bug-fixes.  Some of these are for support of
different terminals; for example, Dashers don't have a conventional
line-feed (it acts as a newline), so we've added a DN termcap function
that can be set to the proper value.  A similar problem occured
because the backspace sequence wasn't being used properly.

You may or may not want the change put into jove.c to put out
visual-end a little later.  I found this useful in dealing with
a terminal which supports multiple windows.  

Here are a few things that we haven't done, but should.
    
    Put function keys into their own section of the keymaps.  At present
    they share the keymap with other keys, and so have been restricted to
    the miscmap.  This prevents the use of any prefix character with
    a function key (but a function key can be a prefix character). This
    isn't a really big problem because there are generally a liberal number
    of function keys, but it would be nice to be able to define ESC <left>
    and so on.
    
    Provide some sort of terminal specific translation of function key
    names, so that describe-key prints function keys as FIND, F12, etc.
    instead of ESC [ 1 ~ and ESC [ 2 4 ~.
	
    Update the documentation to describe Ansi-codes and how to bind 
    ansi function keys.

The following file gives default bindings for a vt200-series terminal.
============================================= New file: vt200.joverc
bind-to-key ansi-codes ^[[
bind-to-key ansi-codes ^[O
bind-to-key ansi-codes ^[^[
bind-to-key ansi-codes ^[^O
bind-to-key search-forward ^[[1~
bind-to-key yank ^[[2~
bind-to-key kill-region ^[[3~
bind-to-key set-mark ^[[4~
bind-to-key previous-page ^[[5~
bind-to-key next-page ^[[6~
bind-to-key describe-key [28~
bind-to-key execute-named-command [29~
============================================ End of vt200.joverc
The following are all context diffs.  They work with patch on our system
(SUN running BSD 4.2 Unix).

*** extend.c		Mon Jun 22 14:44:20 1987
--- extend.c		Mon Jun 22 14:44:21 1987
***************
*** 20,25 ****
--- 20,27 ----
  extern int	getch(),
  		getchar();
  
+ #define DASHER_MAP(x) (((x) % 100) + ((x) / 100) * 32)
+ 
  /* Auto execute code */
  
  #define NEXECS	20
***************
*** 99,107 ****
--- 101,135 ----
  	BindSomething(findmac);
  }
  
+ /*
+ * AnsiKey : return 'key' value for an ANSI-style function 
+ * sequence.  This is the value of the numeric operand for
+ * extended-type functions, or the next character for others.
+ */
+ 
+ int AnsiKey() {
+     int c;
+     int num1 = 0;
+ 
+     c = addgetc();
+     while (isdigit(c)) {
+         num1 = num1*10 + (c - '0');
+         c = addgetc();
+     }
+     while (c == ';' || isdigit(c))
+         c = addgetc();
+     /* Map Dasher functions into 128-byte space */
+     if (c == 'z')
+         num1 = DASHER_MAP(num1);
+     if (c == '~' || c == 'z')
+         return num1;
+       else return c; 
+ }
+ 
  extern int	EscPrefix(),
  		CtlxPrefix(),
  		MiscPrefix();
+ extern int      AnsiCodes();
  
  data_obj **
  IsPrefix(cp)
***************
*** 121,126 ****
--- 149,168 ----
  	return 0;
  }
  
+ data_obj **
+ IsAnsiCode(cp)
+ data_obj	*cp;
+ {
+        int (*proc)();
+ 
+ 	if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION)
+  		return 0;
+ 	proc = ((struct cmd *) cp)->c_proc;
+ 	if (proc == AnsiCodes)
+ 		return miscmap;
+ 	return 0;
+ }
+ 
  unbind_aux(c)
  {
  	if (c == CR || c == LF)
***************
*** 132,137 ****
--- 174,180 ----
  UnbindC()
  {
  	char	*keys;
+         int     lastKey;
  	data_obj	**map = mainmap;
  
  	keys = do_ask("\r\n\01\02\03\04\05\06\010\011\013\014\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037", unbind_aux, (char *) 0, ProcFmt);
***************
*** 142,152 ****
  			break;
  		if ((map = IsPrefix(map[*keys])) == 0)
  			break;
! 		keys++;
  	}
  	if (keys[1] != 0)
  		complain("That's not a legitimate key sequence.");
! 	map[keys[0]] = 0;
  }
  		
  addgetc()
--- 185,211 ----
  			break;
  		if ((map = IsPrefix(map[*keys])) == 0)
  			break;
!                 if (IsAnsiCode(map[*keys])) {
!                     map = miscmap;
!                     lastKey = 0;
!                     ++keys;
!                     while (*keys != '\0' && isdigit(*keys)) {
!                        lastKey = lastKey * 10 + (*keys - '0');
!                        ++keys;
  		    }
+                     if (*keys != 'z' && *keys != '~')
+                         lastKey = *keys;
+                     /* Map Dasher functions into 128-byte space */
+                     if (*keys == 'z')
+                         lastKey = DASHER_MAP(lastKey);
+                     break;
+ 		}
+                      
+ 		lastKey = *++keys;
+  	}
  	if (keys[1] != 0)
  		complain("That's not a legitimate key sequence.");
! 	map[lastKey] = 0;
  }
  		
  addgetc()
***************
*** 193,198 ****
--- 252,259 ----
  	} else {
  		if (nextmap = IsPrefix(map[c]))
  			BindWMap(nextmap, c, cmd);
+ 		else if (IsAnsiCode(map[c]))
+ 			miscmap[AnsiKey()] = cmd;
  		else
  			map[c] = cmd;
  	}
***************
*** 215,220 ****
--- 276,282 ----
  
  DescWMap(map, key)
  data_obj	**map;
+ int             key;
  {
  	data_obj	*cp = map[key],
  			**prefp;
***************
*** 223,228 ****
--- 285,292 ----
  		add_mess("is unbound.");
  	else if (prefp = IsPrefix(cp))
  		DescWMap(prefp, addgetc());
+         else if (IsAnsiCode(cp))
+ 	        DescWMap(miscmap, AnsiKey());
  	else
  		add_mess("is bound to %s.", cp->Name);
  }
***************
*** 519,524 ****
--- 583,589 ----
  {
  	struct variable	*vp;
  	char	prbuf[256];
+ 
  
  	if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
  		return;
*** jove.c	Mon Jun 22 14:45:33 1987
--- jove.c	Mon Jun 22 14:45:34 1987
***************
*** 342,353 ****
  {
  	ttyset(OFF);
  	putpad(KE, 1);
- 	putpad(VE, 1);
  	putpad(TE, 1);
  #ifdef ID_CHAR
  	INSmode(0);
  #endif
  	Placur(ILI, 0);
  	printf("%s", mesg);
  	putpad(CE, 1);
  	flusho();
--- 342,353 ----
  {
  	ttyset(OFF);
  	putpad(KE, 1);
  	putpad(TE, 1);
  #ifdef ID_CHAR
  	INSmode(0);
  #endif
  	Placur(ILI, 0);
+ 	putpad(VE, 1);	/* Relocated, for better visual support */
  	printf("%s", mesg);
  	putpad(CE, 1);
  	flusho();
*** misc.c	Mon Jun 22 14:46:13 1987
--- misc.c	Mon Jun 22 14:46:14 1987
***************
*** 439,444 ****
--- 439,446 ----
  	int	num2;
  	static char *unsupported = "[Unsupported ANSI code received]";
  
+ 	register data_obj	*cp;
+ 
  	while (isdigit(c = getch()))
  		num1 = (num1*10) + (c - '0');
  
***************
*** 478,486 ****
  			ClAndRedraw();
  			break;
  		}
  		/* FALL THROUGH */
  	default:
! 		complain(unsupported);
  	}
  }
  #endif ANSICODES
--- 480,507 ----
  			ClAndRedraw();
  			break;
  		}
+                 break;
+         case 'z':	/* DASHER (ANSI) Function */
+                 num1 = (num1 % 100) + (num1 / 100) * 32;
  		/* FALL THROUGH */
+         case '~':	/* VT220 function */
+ 
+ 		cp = miscmap[num1 % (sizeof(miscmap) / sizeof(miscmap[0]))];
+ 		if (cp == 0) {
+ 			s_mess("[%sunbound]", key_strokes);
+ 			rbell();
+ 		} else
+ 			ExecCmd(cp);
+                 break;
+ 
  	default:
! 		cp = miscmap[c];
! 		if (cp == 0) {
! 			s_mess("[%sunbound]", key_strokes);
! 			rbell();
! 		} else
! 			ExecCmd(cp);
!                 break;
  	}
  }
  #endif ANSICODES
*** screen.c	Mon Jun 22 14:47:16 1987
--- screen.c	Mon Jun 22 14:47:17 1987
***************
*** 144,149 ****
  		if (i_line != CapLine || i_col != CapCol)
  			Placur(i_line, i_col);
! 		if (UL && (c & 0177) == '_' && (*cursor & 0177) != ' ')
! 			putstr(" \b");		/* Erase so '_' looks right. */
  		*cursor++ = c;
  		putchar(c & 0177);
--- 144,154 ----
  		if (i_line != CapLine || i_col != CapCol)
  			Placur(i_line, i_col);
! 		if (UL && (c & 0177) == '_' && (*cursor & 0177) != ' ') {
! 			putstr(" ");		/* Erase so '_' looks right. */
! 			if (BC)
! 				putpad(BC, 1);
! 			else
! 				putchar('\b');
! 		      }
  		*cursor++ = c;
  		putchar(c & 0177);
***************
*** 533,537 ****
  
  	while (--nlines >= 0)
! 		putchar('\n');
  	CapLine = destline;
  }
--- 538,542 ----
  
  	while (--nlines >= 0)
! 		putpad(DN, 1);
  	CapLine = destline;
  }
*** term.c	Mon Jun 22 14:47:50 1987
--- term.c	Mon Jun 22 14:47:50 1987
***************
*** 20,25 ****
--- 20,26 ----
  /* Termcap definitions */
  
  char	*UP,
+ 	*DN,
  	*CS,
  	*SO,
  	*SE,
***************
*** 80,101 ****
  
  /* The ordering of ts and meas must agree !! */
  #ifdef LSRHS
! static char	*ts="vsvealdlspcssosecmclcehoupbcicimdceillsfsrvbksketiteALDLICDCrsrepcip";
  static char	**meas[] = {
  	&VS, &VE, &AL, &DL, &SP, &CS, &SO, &SE,
  	&CM, &CL, &CE, &HO, &UP, &BC, &IC, &IM,
  	&DC, &EI, &LL, &SF, &SR, &VB, &KS, &KE,
  	&TI, &TE, &M_AL, &M_DL, &M_IC, &M_DC,
! 	&RS, &RE, &lPC, &IP, 0
  };
  #else
! static char	*ts="vsvealdlspcssosecmclcehoupbcicimdceillsfsrvbksketiteALDLICDCpcip";
  static char	**meas[] = {
  	&VS, &VE, &AL, &DL, &SP, &CS, &SO, &SE,
  	&CM, &CL, &CE, &HO, &UP, &BC, &IC, &IM,
  	&DC, &EI, &LL, &SF, &SR, &VB, &KS, &KE,
  	&TI, &TE, &M_AL, &M_DL, &M_IC, &M_DC,
! 	&lPC, &IP, 0
  };
  #endif
  
--- 81,102 ----
  
  /* The ordering of ts and meas must agree !! */
  #ifdef LSRHS
! static char	*ts="vsvealdlspcssosecmclcehoupbcicimdceillsfsrvbksketiteALDLICDCrsrepcipdo";
  static char	**meas[] = {
  	&VS, &VE, &AL, &DL, &SP, &CS, &SO, &SE,
  	&CM, &CL, &CE, &HO, &UP, &BC, &IC, &IM,
  	&DC, &EI, &LL, &SF, &SR, &VB, &KS, &KE,
  	&TI, &TE, &M_AL, &M_DL, &M_IC, &M_DC,
! 	&RS, &RE, &lPC, &IP, &DN, 0
  };
  #else
! static char	*ts="vsvealdlspcssosecmclcehoupbcicimdceillsfsrvbksketiteALDLICDCpcipdo";
  static char	**meas[] = {
  	&VS, &VE, &AL, &DL, &SP, &CS, &SO, &SE,
  	&CM, &CL, &CE, &HO, &UP, &BC, &IC, &IM,
  	&DC, &EI, &LL, &SF, &SR, &VB, &KS, &KE,
  	&TI, &TE, &M_AL, &M_DL, &M_IC, &M_DC,
! 	&lPC, &IP, &DN, 0
  };
  #endif
  
***************
*** 154,159 ****
--- 155,163 ----
  		*(meas[i]) = (char *) tgetstr(ts, &termp);
  		ts += 2;
  	}
+ 	
+ 	if (!DN)
+ 		DN = "\n";
  	if (lPC)
  		PC = *lPC;
  	if (XS)
***************
*** 190,193 ****
  	if (CanScroll = ((AL && DL) || CS))
  		IDline_setup(termname);
  }
- 
--- 194,196 ----
*** termcap.h		Mon Jun 22 14:47:57 1987
--- termcap.h	Mon Jun 22 14:47:57 1987
***************
*** 9,14 ****
--- 9,15 ----
  
  extern char
  	*UP,	/* Scroll reverse, or up */
+ 	*DN,	/* down */
  	*CS,	/* If on vt100 */
  	*SO,	/* Start standout */
  	*SE,	/* End standout */
-- 

Jim Patterson          decvax!utzoo!dciem!nrcaer!cognos!jimp
Cognos Incorporated