ml@ecerl3.ncsu.edu (11/26/89)
Greetings! A while back I posted some questions about configuring Emacs on an HP9000 series 300 box (running HP-UX) to work well with X-Windows (X11). The basic question was "How do I enable use of all the extra function keys on my keyboard?". Well, the basic answer was "You can't". It seems that the code in emacs to handle the keyboard under X11 still is somewhat rudimentary. One person suggested that I might want to patch the source to extend this. Several others wrote to me requesting that I fill them in on the correct answer since they had the same problem. First off, apologies to all those who sent me messages and got no reply. I reply to all messages I get, but the mail system here is not set up correctly and so most outgoing mail bounces. I wish the administration would fix that, but they haven't/won't. Oh well. Hopefully the stuff contained here will server as an adequate response. So, here goes.... ----------------------------------------------------------------------------- The problem lies in the source file x11term.c, where you will need to change some things. Included below is a fragment from that file showing what it looks like after the changes I made. By comparing this to the original file you should have no difficulties making these changes. By way of a disclaimer, I shall note in advance that what I have done here does not necessarily represent the best way to do things. In particular, I have made no attempt whatsoever to make the key sequences map to anything that you will find on an existing terminal (ie. I haven't tried to emulate anything). I just did a quick and dirty hack which gave me nearly total control over the keyboard. First off, some documentation on what I did: I have patched src/x11term.c for the HP 9000 s 300 workstations so as to enable use of all the extra keys on the keyboard, as well as recognizing some conventional keys with unconventional modifiers (such as Ctrl-Return). In any case where a key is treated specially (ie, doesn't map into a single ASCII character), you get a five character escape sequence, consisting of the characters 'ESC' and '[' followed by three hex digits, i.e.: ESC [ #1 #2 #3 where the #1 #2 #3 are each an ASCII hex digit (characters in the range '0' to '9' and 'A' through 'F'). #1 = state The character gives the state of the modifier keys (the control, shift, and meta keys). Bit 0 will be set if the shift key is down; Bit 2 will be set if the control key is down; Bit 3 will be set if the meta ("Extend Char") key is down. Bit 1 is the bit for the CapsLock key, but I always strip this off so you won't see it set. So, the possible values for #1 are: 0 No modifier keys down 1 Shift 4 Control 5 Shift Control 8 Meta (Alt) 9 Shift Meta C Control Meta D Shift Control Meta Remember that this binary value is sent as an ASCII hex digit, not in raw binary form. #2#3 = key These are the lower order byte of the keysym, expressed as two hex digits. Look in <X11/keysymdef.h> to see what all the keysyms are. The HP "Vendor specific" keys, which don't have standard keysyms, are remapped into standard keysyms, mostly F35, F34 ... For example, if I hold the control key down and press the "Select" button, this will be translated into the key sequence: ESC [ 4 6 0 | | | | | prefix ----------+--+ | +-+--------- Low order byte of keysym. Keysym | for "Select" button is XK_Select, | which is 0xFF60. | Control down ---------+ Quick reference of all the special keys on the HP 9000s300 keyboard, and how I map them. Key label: #2#3 Associated X11 keysym Notes ------------ ---- --------------------- ------------------ Cursor control, editing keys, miscellany: BackSpace 08 XK_BackSpace 1 Tab/BackTab 09 XK_Tab 1,2 Return 0D XK_Return 1 Escape 1B XK_Escape 1,3 Delete FF XK_Delete 1,3 Menu 67 XK_Menu Stop 69 XK_Cancel Reset/Break 6B XK_Break Home 50 XK_Home LeftArrow 51 XK_Left UpArrow 52 XK_Up RightArrow 53 XK_Right DownArrow 54 XK_Down Prev 55 XK_Prior Next 56 XK_Next Select 60 XK_Select Print/Enter 62 XK_Execute User/System E0 XK_F35 ClearLine DF XK_F34 ClearDisplay DE XK_F33 InsertLine DD XK_F32 DeleteLine DC XK_F31 InsertChar DB XK_F30 DeleteChar DA XK_F29 The function keys: F1 BE XK_F1 F2 BF XK_F2 F3 C0 XK_F3 F4 C1 XK_F4 F5 C2 XK_F5 F6 C3 XK_F6 F7 C4 XK_F7 F8 C5 XK_F8 The keypad keys (note 4 applies for all): 0 B0 XK_KP_0 1 B1 XK_KP_1 2 B2 XK_KP_2 3 B3 XK_KP_3 4 B4 XK_KP_4 5 B5 XK_KP_5 6 B6 XK_KP_6 7 B7 XK_KP_7 8 B8 XK_KP_8 9 B9 XK_KP_9 * AA XK_KP_Multiply + AB XK_KP_Add , AC XK_KP_Separator - AD XK_KP_Subtract . AE XK_KP_Decimal / AF XK_KP_Divide Enter 8D XK_KP_Enter Tab/BackTab 89 XK_KP_Tab 2 The PF keys (4 keys above the numeric keypad): PF1 91 XK_KP_F1 PF2 92 XK_KP_F2 PF3 93 XK_KP_F3 PF4 94 XK_KP_F4 Notes: 1. Backspace, return, etc. just map into ASCII code unless Control or Shift key used in conjunction with them. 2. Backtab always sent as escape sequence, even though Tab may not always be. Backtab is sent as "Shifted Tab" esc. sequence rather than being mapped into XK_BackTab. Similarly for Keypad Tab key. 3. Although Delete is Shift+Esc on HP keyboard, these are treated as if they were separate keys. Shift bit in state byte will always be clear for both of these (shifted Esc is remapped into unshifted Delete). 4. If none of shift/control/alt are pressed, the keypad keys will just send appropriate ASCII code, not an escape sequence. ====================================================================== Here are some elisp code fragments showing how you can make use of these key mappings: These lines are at the end of my .emacs file: (if (and (eq window-system 'x) (eq system-type 'hpux) ) (load "Xkeys") ) and here is my file Xkeys.el (note: the function "define-keys" used below is not part of distributed emacs, it's something in my .emacs file. You should be able to get the gist of what's going on though): ====== begin XKeys.el ======== (message "loading HPUX X11 key-bindings") (defvar FCN-map (make-keymap) "Keymap for function-key sequences") (defvar SFCN-map (make-keymap) "Keymap for shift-function-key sequences") (defvar CFCN-map (make-keymap) "Keymap for control-function-key-sequences") (defvar MFCN-map (make-keymap) "Keymap for meta-function-key-sequences") (defvar CSFCN-map (make-keymap) "Keymap for control-shift-function-key sequences") (defvar MSFCN-map (make-keymap) "Keymap for meta-shift-function-key sequences") (defvar MCFCN-map (make-keymap) "Keymap for meta-control-function-key sequences") (defvar MCSFCN-map (make-keymap) "Keymap for meta-shift-control-function-key sequences") (define-key global-map "\e[" nil) (define-key global-map "\e[0" FCN-map) (define-key global-map "\e[1" SFCN-map) (define-key global-map "\e[4" CFCN-map) (define-key global-map "\e[5" CSFCN-map) (define-key global-map "\e[8" MFCN-map) (define-key global-map "\e[9" MSFCN-map) (define-key global-map "\e[C" MCFCN-map) (define-key global-map "\e[D" MCSFCN-map) (define-keys FCN-map '( ("50" 'other-window) ("51" 'backward-char) ("52" 'previous-line) ("53" 'forward-char) ("54" 'down-arrow) ("55" 'scroll-down) ("56" 'scroll-up) ("60" 'set-mark-command) ("67" 'help-command) ("BE" rect-map) ("DA" 'delete-char) ("DC" 'kill-whole-line) ("DB" 'quoted-insert) )) (define-keys SFCN-map '( ("50" 'other-window) ("51" 'beginning-of-line) ("52" 'previous-line) ("53" 'end-of-line) ("54" 'down-arrow) ("55" 'scroll-down) ("56" 'scroll-up) ("60" 'set-mark-command) ("67" 'help-command) ("BE" rect-map) ("DA" 'delete-char) ("DC" 'kill-whole-line) ("DB" 'quoted-insert) )) ====== end of XKeys.el ======== And finally, here is the fragment from x11term.c which contains the modifications I made: ====== begin x11term.c.changes ====== /* * 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"); ... ... ... default: return ("-1"); } } #else #ifndef HPUX /* Add this line */ char * stringFuncVal(keycode) KeySym keycode; { switch (keycode) { case XK_F1: return ("11"); case XK_F2: return ("12"); ... ... ... default: return ("-1"); } } #endif /* Add this line */ #endif /* not sun */ #ifdef HPUX /* Add this block */ #define IsTTYKey(K) ( ((K) >= XK_BackSpace) && ((K) <= XK_Escape) && \ ((K) != XK_Clear) ) char hexdigit[] = "0123456789ABCDEF"; int TranslateKey(keysym, xbuf, state) int keysym; char * xbuf; int state; { register int nbytes; register char * ptr; state &= ShiftMask | ControlMask | Mod1Mask; ptr = xbuf; nbytes = 0; /* As long as they are not holding down the shift or control or meta * keys, we send keypad keys and TTY keys (backspace, return, et al) * as regular ASCII characters rather than special escape codes. * For TTY keys, Meta key does the expected thing (setting high bit). * * Holding shift/control/meta keys down in conjunction with these * special keys (except meta with TTY keys) causes escape sequences * to be sent, as per our normal "Function key" code. */ if ( ( (IsTTYKey(keysym)) && ! (state & (ShiftMask|ControlMask)) ) || ( (IsKeypadKey(keysym)) && ! (state) && ! (IsPFKey(keysym)) ) || ( (keysym == XK_Delete) && ! (state & ControlMask) ) ) /* XK_Delete is singled out from the rest of the TTY type keys * because on HP keyboard it is gotten by Shift-Esc, which means * that the shift bit will always be set in the 'state' variable. */ { keysym &= 0x7F; /* Convert to ASCII */ if (state & Mod1Mask) keysym |= 0x80; /* if Metakey... */ *ptr++ = keysym; *ptr = 0; return(1); } /* Remap some special keys */ # define Remap(old,new) \ case old: keysym = new; break; switch(keysym) { Remap(XK_KP_BackTab, XK_KP_Tab); Remap(XK_BackTab, XK_Tab); Remap(XK_Print, XK_Execute); Remap(XK_Reset, XK_Break); Remap(XK_System, XK_F35); Remap(XK_User, XK_F35); /* Same key as XK_System */ Remap(XK_ClearLine, XK_F34); Remap(XK_Clear, XK_F33); Remap(XK_InsertLine, XK_F32); Remap(XK_DeleteLine, XK_F31); Remap(XK_InsertChar, XK_F30); Remap(XK_DeleteChar, XK_F29); Remap(XK_Muhenkan, XK_F28); /* What the heck are these? */ Remap(XK_Henkan, XK_F27); } # undef Remap *ptr++ = 033; /* Esc */ *ptr++ = '['; *ptr++ = hexdigit[state]; *ptr++ = hexdigit[ (keysym>>4) & 0xF ]; *ptr++ = hexdigit[ keysym & 0xF ]; *ptr = 0; return(ptr-xbuf); } #endif internal_socket_read(bufp, numchars) register unsigned char *bufp; register int numchars; { /* Number of keyboard chars we have produced so far. */ int count = 0; int nbytes, rows, cols; char mapping_buf[20]; ... ... ... case LeaveNotify: CursorToggle(); CursorOutline = 1; CursorToggle(); break; #ifdef HPUX /* * 01 Nov 89 Mark Lanzo * Complete replacement of KeyPress code for HP9000s300/HPUX. * Ideal treatment would be to have XLookupString do our work * for us, plus elisp hooks for changing things. Here though * I'm using the same methodology that original code used, but * have modified how all special keys are handled. */ case KeyPress: nbytes = XLookupString(&event, mapping_buf, 20, &keysym, 0); /* * All special keys (and a few regular keys) have keysym * codes which are more than 1 byte, so I check for nonzero * bits beyond l.s.byte. Regular ASCII characters for most * part have keysyms which match, so if upper bytes of keysym * are clear I just accept them as they are (including * meta characters which I don't feel should be treated * specially). */ if (IsModifierKey(keysym)) break; /* * Discard XLookupString's result if special key pressed. * In effect, we use our own LookupString fcn in this case, * although we accept XLookupString's value for keysym. */ if (keysym & ~0xFF) nbytes = TranslateKey(keysym, mapping_buf, event.xkey.state); else if ( (nbytes==1) && (event.xkey.state & Mod1Mask) ) *mapping_buf |= 0x80; /* We now return you to your regularly scheduled code ... :-) */ if (nbytes && (nbytes < numchars)) { bcopy(mapping_buf, bufp, nbytes); bufp += nbytes; count += nbytes; numchars -= nbytes; } break; #else case KeyPress: nbytes = XLookupString(&event, mapping_buf, 20, &keysym, 0); /* * 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, "\033[D"); 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, "\033[B"); nbytes = 1; break; } } if (nbytes) { if (event.xkey.state & Mod1Mask) *mapping_buf |= METABIT; if (numchars - nbytes > 0) { bcopy(mapping_buf, bufp, nbytes); bufp += nbytes; count += nbytes; numchars -= nbytes; } } break; #endif /* HPUX */ case ButtonPress: case ButtonRelease: *bufp++ = (char) 'X' & 037; ++count; ====== end of x11term.c.changes ====== ==[ ml@eceris.ncsu.edu (128.109.135.109) ]==