📄 oemacs.w
字号:
@<Put a tty subwindow into the frame@>=argv[0]="emacs";putenv("TERM=sun");tty=(Tty)xv_create(frame,TTY,WIN_IS_CLIENT_PANE,@| TTY_QUIT_ON_CHILD_DEATH,TRUE,@| TTY_ARGV,argv,NULL);@ @<Global...@>=Tty tty;@ @<Include...@>=#include <xview/tty.h>@ The XView manual doesn't tell us that tty subwindows have a view partand a pseudo-terminal part. (The manual does mention briefly that textsubwindows have views---at the beginning of section 6.3, and indirectly inone of the examples in the chapter on color.)The view window of an emulated tty will receive keyboard andmouse events. We need to know its ``handle,'' because we want tomodify XView's default interpretation of many of those events.For example, we want to grab the keyboard focus (i.e., to begin receivingkeyboard input) as soon as the user moves the mouse into the \.{emacs}window. The normal OpenLook default requires a user to click in the windowfirst, but that is inefficient in a production book-writing environment.Us \.{emacs} users would rather type than point.A secret incantation makes the view window accessible. Dear reader,would you have guessed how to do this, from reading the manuals only,without looking at Jeff Peck's code? Be honest now.We don't have to enable the notification of other kinds of events;tty subwindows already do that.@<Prepare to be notified when the mouse enters the window@>=window=(Xv_window)xv_get(tty,OPENWIN_NTH_VIEW,0);xv_set(window,WIN_CONSUME_EVENT,LOC_WINENTER,NULL);@ @<Global...@>=Xv_window window; /* the view window of |tty| */@ If the user has specified reverse video with the \.{-rv} option,we will reverse black and white in the mouse cursor. This will make itmore visible against a black background.Changing the cursor is another undocumented reason why we need to knowabout the tty's view window; nothing changes if we try to attachthe new cursor to |frame| or to |tty| instead of to |window|.@<Change the cursor, to avoid black-on-black@>=if (rv) {Xv_singlecolor white,black; Xv_cursor cursor; white.red=white.green=white.blue=255; black.red=black.green=black.blue=0; cursor=(Xv_cursor)xv_create(NULL,CURSOR,@| CURSOR_SRC_CHAR,OLC_BASIC_PTR,CURSOR_MASK_CHAR,OLC_BASIC_MASK_PTR,@| CURSOR_FOREGROUND_COLOR,&white,CURSOR_BACKGROUND_COLOR,&black,NULL); xv_set(window,WIN_CURSOR,cursor,NULL);}@ @<Include...@>=#include <xview/cursor.h> /* we're using the cursor package */@ What is the variable |rv| that was tested in the code above? Good question.We have to scan for \.{-rv} before |xv_init| looks at the command arguments.@<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>=rv=0;{@+int k=argc; while (--k>0) if (strcmp(argv[k],"-rv")==0 || strcmp(argv[k],"-reverse")==0) rv=1;}@ @<Global...@>=int rv;@ We need to know the height and width of characters in the font, in orderto convert mouse positions into coordinates that \.{emacs} will like.If the user has specified a font explicitly, the font will presumably havea fixed width for all characters; we can learn the relevant dimensionsby calling |xv_get|. But if the user has not specified a font, thesituation is trickier; |xv_get| will report the width of the default{\it non\/}-fixed-width font, and this will probably differ from the width ofthe actual fixed-width font the tty subwindow will choose.Curiously, if we call |xv_find(NULL,FONT,FONT_FAMILY,FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL)| {\it before\/} calling |xv_init|,without even doing anything with the result returned by |xv_find|,|xv_init| will not install any fonts specified on the command line.The trick we used for icons---installing the default gnu icon on the firstcall to |xv_create|---will therefore fail.Thus, we have to work around two distinct bugs in XView. The solutionis to discover the effects of the user's command line after |xv_init|has acted and the frame has been set up; we can determine by brute force whatfont will go into the tty window. The program below works correctlyeven if the command line specifies \.{-scale} \.{large}, say, instead ofspecifying a new font explicitly by something like \.{-font} \.{9x15}.While we are cataloguing peculiarities of XView, we might as well mentionthat the default character dimensions of the default font (Lucida) arereported to be $8\times13$ in the 12-point (medium) size, $8\times15$ in the14-point (large) size, and $12\times20$ in the 19-point (extralarge) size.The actual character dimensions in the window come, however, from thedefault fixed-width font (Lucida typewriter), and they are $7\times13$,$9\times15$, and $11\times23$ in the same three sizes. No logical progressionis evident in either the variable-width or the fixed-width dimensions,although Lucida is a ``scalable font family.''@<Compute the height and width of characters in the font@>={ Xv_font font=(Xv_font)xv_get(frame,XV_FONT); Xv_font dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY, FONT_FAMILY_DEFAULT,NULL); if (strcmp((char*)xv_get(font,FONT_NAME), (char*)xv_get(dfont,FONT_NAME))==0) { /* the user didn't specify a new font by name */ dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY, FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL); /* this one will be used by the tty window */ } else dfont=font; char_width=(int)xv_get(dfont,FONT_DEFAULT_CHAR_WIDTH); char_height=(int)xv_get(dfont,FONT_DEFAULT_CHAR_HEIGHT);}@ @<Global...@>=int char_width, char_height; /* character dimensions in the font */@ @<Include...@>=#include <xview/font.h> /* header for the font package */@ OK, we've figured out how to install a tty subwindow with the rightevent mask and the right cursor, and how to calculate the sizes of thecharacters it will contain. All that remains is for us to do theseoperations in the proper order, and to specify a filter routine thatwill monitor and edit all communications between the keyboard and theEmacs processor in the window.The new ingredient is the filter specification. We tell the XViewnotifier to call |filter| when a window event occurs, instead ofletting it call the tty subroutine event handler directly. The parameter|NOTIFY_SAFE| implies that the window's event handler ispart of XView, not an alien routine.@<Install the components...@>=@<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>;xv_init(XV_INIT_ARGC_PTR_ARGV,&argc,argv,NULL); /* start XViewing; strip and remember the OpenWin arguments */@<Create a frame with the gnu icon@>;@<Remove the frame header...@>;@<Put a tty subwindow into the frame@>;@<Prepare to be notified when the mouse enters the window@>;@<Change the cursor, to avoid black-on-black@>;@<Compute the height and width of characters in the font@>;notify_interpose_event_func(window,filter,NOTIFY_SAFE);@* Keyboard events.The job of an interposed filter function is to look at an event andeither process it ourselves or pass it through (possibly modified)to its normal recipient. In the first case we return the codevalue |NOTIFY_DONE|, since we aren't reporting any errors;in the second case we call the normal event handler and return the valueit returns to us.An XView event is a data structure that has been partiallyinterpreted by the XView routines, which add semantic sugar tothe complex union type of X~Window events. We need not looktoo far inside an event structure to do the things that concern us.And what is our job? We are looking for three different kinds of events:\smallskip\itemitem{(1)} When the mouse enters the window,we want to grab the keyboard focus.\itemitem{(2)} When a mouse button goes up or down, and we have the keyboardfocus, we want to send a coded sequence of characters to \.{emacs}.\itemitem{(3)} When a key goes down, and we have the keyboard focus, wewant to send an appropriate sequence of characters to \.{emacs}.\itemitem{(4)} When the status of the Num Lock indicator light changes, wewill send emacs the command {\tt turn-numlock-on} or {\tt turn-numlock-off},for reasons described below.\smallskip\noindent Other events, like instructions to repaint orresize the window, will be passed through without change to the tty window.@<Event-handling...@>=Notify_value filter(window,event,arg,type) Xv_window window; /* the ``client'' on whom we interposed */ Event *event; /* the data we are filtering */ Notify_arg arg; /* optional communication parameter between clients */ Notify_event_type type; /* |NOTIFY_SAFE| or |NOTIFY_IMMEDIATE| */{@+register int id=event_id(event);#ifdef DEBUG printf("event %d%s, action %d, shift %x, mouse(%d,%d)\n", event_id(event),event_is_up(event)?"UP":"DOWN",event->action, event_shiftmask(event),event_x(event),event_y(event));#endif @<Update the Num Lock status@>; if (id==LOC_WINENTER) @<Grab the keyboard focus and return@>; if (event_is_button(event)) @<Translate a mouse event and return@>; if (event_is_up(event)) return NOTIFY_DONE; /* key has been released */ @<Translate a function key into a special escape sequence@>; @<Sanitize a keypress event so that unusual semantic actions are removed@>; return notify_next_event_func(window,event,arg,type); /* pass it through */}@ It's easy to take charge of the keyboard and mouse, as soon as the mouseenters our territory.@<Grab...@>={ win_set_kbd_focus(window,xv_get(window,XV_XID)); return NOTIFY_DONE;}@ If the event is not related to mouse buttons or special function keys,we want to pass it on unchanged, unless its |event_id| is less than 128.In that case, it represents a character code, and we want to nuke anysemantic ``keyboard acceleration'' actions it might have been assignedby OpenWindows.We also make the Meta key add 128 here. An undocumented macrocalled |event_set_id|, found in \.{<xview/win\_input.h>},clears the |action| code as desired.@<Sanitize...@>=if (id<128) if (event_meta_is_down(event)) event_set_id(event,id+128); else event_set_action(event,ACTION_NULL_EVENT);@* Function keys.The Sun Type 4 keyboard has lots of keys, and these can be bound to lotsof useful functions when we are \.{emacs}ing to the max. Besides theletters and punctuation marks of a normal typewriter, there are ten``left'' function keys, L1--L10; twelve ``top'' function keys, F1--F12;fifteen ``right'' function keys, R1--R15; and eight additional keyslabeled Help, Alt, AltGraph, Ins, Del, Enter, $+$, $-$, which we willpretend have been labeled B1--B8.The L5 key, also known as Front, is controlled by the Open Lookwindow manager; it makes a window rise above any that might overlap it,or shoves the window underneath in case it already was on top.The L7 key, aka Open, is likewise preempted by thewindow manager. It closes a frame to an icon, or opens an icon.The window manager traps the R2 key and calls it the ``language'' key;but I have no use for that feature. So I have remapped R2 to the comparativelyuseless character $3\over4$, and I will translate it back to R2 below. (The\.{xmodmap} program allows users to reassign the interpretation of key codes.)I could have recovered the L5 and L7 keys in the same way, but I liketheir functions as they stand. (L5 and L7 still come through if aShift, Control, and/or Meta key is down.)I can never remember the difference between Delete and BackSpace, so Ihave mapped them both into control-?, ASCII code 127.There are two Shift keys, one at the left and one at the right, whichare best kept indistinguishable from each other. Similarly, the leftand right Meta keys (`\.{\char27}') are essentially identical. There's aControl key too. These three types of modifier keys generate keypressevents, but we ignore them; the only thing that matters to us is whetherthey are currently up or down, when other keys are pressed.\font\ttit=cmitt10There also are three special keys that do not generate events, so wenever see them. The CapsLock key toggles the Caps Lock light andchanges lowercase letters to uppercase when the light is on. TheNumLock key toggles the Num Lock light and changes the interpretationof R4--R15 and B4--B8 when that light is on. The Compose key turns theCompose light on until you type two characters, then it produces aspecial symbol if those two characters match a pattern. For example,when Compose is followed by either \.{a"} or \.{"a} you get the 8-bitISO code for {\tt \"a}; when Compose is followed by either \.{th} or\.{ht} you get the Icelandic thorn; when it's followed by \.{??} you get {\tt?`}; \.{c/} and \.{L-} give \rlap{\./}\.c and {\ttit\char`\$}and so on. (A list of all composition patternsappears in \.{<X11/Suncompose.h>}, but not in any of the manualsI've seen.) The light goes off after two characters have beentyped, or if your first character is not composable, or ifyou hit Compose again prematurely. If no proper two-character patternwas specified, only ``up'' events (key releases) are transmitted, andnothing will pass through to \.{emacs}.One other feature is worth noting: The key between F12 and Deleteproduces a backslash `\.\\', or a vertical line `\.{\char125}' whenshifted. Everybody knows that, but even more is true. If you hold theAltGraph key down and press this key, it turns out that you get thebroken-bar character `{\tt\hbox to1em{\hss\vbox{\hrule width 1pt height3pt\vskip1.5pt\hrule height2pt depth1pt}\hss}}'. This is the only key that theengineers chose to endow with three different graphic symbols.A few other anomalies occur; for example, AltGraph-R1 gives ASCII null,while AltGraph does not affect R4. But I didn't discover any additional
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -