tbray@watsol.waterloo.edu (Tim Bray) (05/02/89)
I run GNUmacs 18.52, and recently replaced the overpriced, oversized, noisy
Sun3 on my desk with a nice NCD16 X terminal. Will review it on comp.windows.x
sometime soon. Had no end of trouble teaching Emacs about it though; the
function keys are quite a bit like those on a DEC screen, but a lot of them
were generating unhelpful things like ^[[-1z. Went and looked at x11term.c and
was suprised by the way keys are handled; a hardcoded case statement mapping X
keysyms to a totally non-intuitive non-mnemonic set of funny numbers; further,
the case statement was conditionalized based on whether this was a Sun or not;
further, the arrow keysyms were mapped to C-N, C-P, etc. hardcoded at the C
level, sigh...
A bit of thought and I couldn't see any reason why it wouldn't be better just
to return the CSI-map prefix with the X keysyms. So x11term.c became 174 lines
shorter, and now when I press F3, emacs sees '^[[F3', and when I press
'Insert', emacs sees '^[[Insert'. I have a term-ncd file that has intelligent
lines such as
(define-key CSI-map "Insert" 'copy-region-as-kill)
(define-key CSI-map "Home" 'execute-extended-command)
(define-key CSI-map "F4" 'split-window-vertically)
There was one gotcha; since F1 is a prefix of F10 through F12, I had to use
xmodmap in my X startup to cause F1 to generate an unused keysym, in my case
KP_F1, and to set F1, I have:
(define-key CSI-map "KP_F1" 'other-window) ;;; F1
One other gotcha. So far, the `num lock' key, in the position which I have
always used for universal-argument, is set so that it alternately generates
KeyPressed and KeyReleased events (STUPID STUPID STUPID); maybe there's a way
to fix this but I haven't found it.
My apologies if this is a well-known problem fixed in a subsequent version.
But I would really appreciate hearing if what I'm doing here is Totally Wrong
and a Danger to the People. Anyhow, at the end of a message is a diff -cb
against 18.52 x11term.c. But it's easier to describe what to do:
1. Around line 1051 is the function stringFuncVal. Nuke the whole thing.
2. Around line 1322, in the function internal_socket_read, in the big switch on
the X event type, in `case Keypress:', The stock version sez:
/* Someday this will be unnecessary as we will
be able to use XRebindKeysym so XLookupString
will have already given us the string we want. */
if (IsFunctionKey(keysym) ||
IsMiscFunctionKey(keysym)) {
strcpy(mapping_buf,"[");
...many more lines....
case XK_Down:
strcpy(mapping_buf,"\016");
nbytes = 1;
break;
}
}
Replace this with:
/* Someday this will be unnecessary as we will
be able to use XRebindKeysym so XLookupString
will have already given us the string we want. */
/* Perhaps, but why not just use the keysym, since that's what's on
top of the key and makes setting up term-XXX files nice and
intuitive? */
if (IsFunctionKey(keysym) ||
IsMiscFunctionKey(keysym) ||
IsPFKey(keysym) ||
IsKeypadKey(keysym) ||
IsCursorKey(keysym)) {
strcpy(mapping_buf,"\033[");
strcat(mapping_buf,XKeysymToString(keysym));
nbytes = strlen(mapping_buf);
}
Cheers, Tim Bray, New OED Project, tbray@watsol.waterloo.edu
-------------For completeness, here's the diff -cb-----------------
*** /usr/software/emacs/src/x11term.c Wed Dec 7 20:28:00 1988
--- x11term.c Mon May 1 18:18:18 1989
***************
*** 1049,1210 ****
return (internal_socket_read (bufp, numchars));
}
- /*
- * Interpreting incoming keycodes. Should have table modifiable as needed
- * from elisp.
- */
-
- #ifdef sun
- char *stringFuncVal(keycode)
- KeySym keycode;
- {
- switch (keycode) {
- case XK_L1:
- return("192");
- case XK_L2:
- return("193");
- case XK_L3:
- return("194");
- case XK_L4:
- return("195");
- case XK_L5:
- return("196");
- case XK_L6:
- return("197");
- case XK_L7:
- return("198");
- case XK_L8:
- return("199");
- case XK_L9:
- return("200");
- case XK_L10:
- return("201");
-
- case XK_R1:
- return("208");
- case XK_R2:
- return("209");
- case XK_R3:
- return("210");
- case XK_R4:
- return("211");
- case XK_R5:
- return("212");
- case XK_R6:
- return("213");
- case XK_R7:
- return("214");
- case XK_R8:
- return("215");
- case XK_R9:
- return("216");
- case XK_R10:
- return("217");
- case XK_R11:
- return("218");
- case XK_R12:
- return("219");
- case XK_R13:
- return("220");
- case XK_R14:
- return("221");
- case XK_R15:
- return("222");
-
- case XK_Break: /* Sun3 "Alternate" key */
- return("223");
-
- case XK_F1:
- return("224");
- case XK_F2:
- return("225");
- case XK_F3:
- return("226");
- case XK_F4:
- return("227");
- case XK_F5:
- return("228");
- case XK_F6:
- return("229");
- case XK_F7:
- return("230");
- case XK_F8:
- return("231");
- case XK_F9:
- return("232");
-
- default:
- return("-1");
- }
- }
- #else
- char *stringFuncVal(keycode)
- KeySym keycode;
- {
- switch (keycode) {
- case XK_F1:
- return("11");
- case XK_F2:
- return("12");
- case XK_F3:
- return("13");
- case XK_F4:
- return("14");
- case XK_F5:
- return("15");
- case XK_F6:
- return("17");
- case XK_F7:
- return("18");
- case XK_F8:
- return("19");
- case XK_F9:
- return("20");
- case XK_F10:
- return("21");
- case XK_F11:
- return("23");
- case XK_F12:
- return("24");
- case XK_F13:
- return("25");
- case XK_F14:
- return("26");
- case XK_F15:
- return("28");
- case XK_Help:
- return("28");
- case XK_F16:
- return("29");
- case XK_Menu:
- return("29");
- case XK_F17:
- return("31");
- case XK_F18:
- return("32");
- case XK_F19:
- return("33");
- case XK_F20:
- return("34");
-
- case XK_Find :
- return("1");
- case XK_Insert:
- return("2");
- case XK_Delete:
- return("3");
- case XK_Select:
- return("4");
- case XK_Prior:
- return("5");
- case XK_Next:
- return("6");
- default:
- return("-1");
- }
- }
- #endif /* not sun */
-
internal_socket_read(bufp, numchars)
register unsigned char *bufp;
register int numchars;
--- 1049,1054 ----
***************
*** 1326,1362 ****
/* Someday this will be unnecessary as we will
be able to use XRebindKeysym so XLookupString
will have already given us the string we want. */
if (IsFunctionKey(keysym) ||
! IsMiscFunctionKey(keysym)) {
! strcpy(mapping_buf,"[");
! strcat(mapping_buf,stringFuncVal(keysym));
! #ifdef sun
! strcat(mapping_buf,"z");
! #else
! strcat(mapping_buf,"~");
! #endif /* sun */
nbytes = strlen(mapping_buf);
}
! else {
! switch (keysym) {
! case XK_Left:
! strcpy(mapping_buf,"\002");
! nbytes = 1;
! break;
! case XK_Right:
! strcpy(mapping_buf,"\006");
! nbytes = 1;
! break;
! case XK_Up:
! strcpy(mapping_buf,"\020");
! nbytes = 1;
! break;
! case XK_Down:
! strcpy(mapping_buf,"\016");
! nbytes = 1;
! break;
! }
! }
if (nbytes) {
if (event.xkey.state & Mod1Mask)
*mapping_buf |= METABIT;
--- 1170,1188 ----
/* Someday this will be unnecessary as we will
be able to use XRebindKeysym so XLookupString
will have already given us the string we want. */
+ /* Perhaps, but why not just use the keysym, since that's what's on
+ top of the key and makes setting up term-XXX files nice and
+ intuitive? */
if (IsFunctionKey(keysym) ||
! IsMiscFunctionKey(keysym) ||
! IsPFKey(keysym) ||
! IsKeypadKey(keysym) ||
! IsCursorKey(keysym)) {
! strcpy(mapping_buf,"\033[");
! strcat(mapping_buf,XKeysymToString(keysym));
nbytes = strlen(mapping_buf);
}
!
if (nbytes) {
if (event.xkey.state & Mod1Mask)
*mapping_buf |= METABIT;