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;