oemacs.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:38k
- datethis
- @i xview_types.w
- @* Introduction.
- This program provides an interface between the GNU Emacs editor and the
- OpenWindows environment, using the XView toolkit for interactive graphics.
- It is based on .{emacstool}, a SunView interface written by Jeff Peck
- of Sun Microsystems in 1986 and adapted by him in 1988 to .{xvetool},
- an early XView interface. The present code, by Don Knuth, is designed to work
- with OpenWindows Version~3 as distributed in 1992, using a Sun Type~4
- keyboard.
- GNU Emacs is a highly portable and versatile program, which does most
- of the hard work involved in editing files. Our job is simply twofold:
- To get .{emacs} started in an appropriate window, and to transmit
- keyboard and mouse events as sequences of characters that .{emacs}
- can happily consume. These simple tasks do, however, require us to
- get a lot of fussy details right. In fact, this program could not have been
- written without a good deal more knowledge about XView than can be found
- in the manuals. Fortunately Jeff Peck works for Sun, and his
- inside knowledge has provided the necessary clues. (All complaints below
- about the XView documentation are based on the reference manuals and
- programming manuals available from Sun and from O'Reilly AM Associates, in
- the summer of 1992. Let us hope that such problems will not persist;
- computer programming should be fun, but some of the code below was
- written only after a bitter struggle!)
- The command-line arguments to .{oemacs} are either standard XView
- arguments, which specify the font and the size and position of the window,
- the icon, the colors, etc.; or they are standard arguments of .{emacs},
- which typically specify the file to be edited and a position in that file.
- If I decide later to make certain things in .{oemacs} less hardwired,
- I will look for options in the X resource database instead of on the
- command line.
- An important note about using .{xmodmap} to change the behavior of
- certain keys appears below. It makes .{emacs} more powerful, unless you
- have other good uses for those keys. (See the entry for .{xmodmap}
- in the index.)
- Before using .{oemacs}, you must compile .{emacs} with the
- .{sunfns} module (which the .{Makefile} will do for you if you've
- configured it correctly), and you should include the lines
- $$vbox{halign{.{#}hfilcr
- (load-library "sun-mouse")cr
- (load-library "sun-fns")cr}}$$
- in Emacs's file .{lisp/site-init.el}.
- Caution: This program was developed and tested with Peck's improved
- versions of sun-mouse and sun-fns; these are available from
- .{peck@@sun.com} if not yet part of the GNU distribution.
- @ We follow the traditional structure of XView applications. The |exit|
- statement at the end is important, because .{oemacs} can be invoked by
- the .{system} command in TEX/ (when the user has typed .e in response
- to an error message); without |exit(0)|, TEX/ would complain of trouble
- executing this program, although we would simply be terminating the program
- without returning any particular value.
- @c
- @<Include header files@>@;
- @#
- Frame frame; /* the base frame where we will live */
- @<Global variables@>@; /* additional globals besides |frame| */
- @#
- @<Event-handling procedures@>@;
- @#
- main(argc,argv)
- int argc;@+char *argv[]; /* typical UNIX/ setup */
- {
- @<Special initialization@>;
- @<Install the components and controls of |frame|@>;
- xv_main_loop(frame);
- exit(0);
- }
- @ Including the header file .{<xview/xview.h>} also causes other
- basic header files like .{<xview/frame.h>}, .{<xview/icon.h>}, etc.,
- to be loaded. We must call the CEE/ compiler with the flag
- .{-I$(OPENWINHOME)/include} so that the CEE/ preprocessor will
- find the OpenWindows header files.
- Some UNIX/ systems define string functions in .{<string.h>}, some in
- .{<strings.h>}; the Sun documentation calls for .{<string.h>}. My
- experiments indicate that Sun's compiler and loader work perfectly
- well with string functions even when no header files are given, so the
- programmer doesn't really have to remember the right name. Similarly,
- .{<stdio.h>} isn't really needed with Sun's CEE/, unless certain macros
- are used. I'll include .{<string.h>} and .{<stdio.h>} anyway, in the
- spirit of being obedient to the stated rules.
- @<Include...@>=
- #include <string.h>
- #include <stdio.h>
- #include <xview/xview.h>
- @* The icon and frame.
- First we attach an icon that will appear if the user closes the .{oemacs}
- window later.
- There are two reasons for doing this first. One is that we might as well
- begin with an easy task, in order to get warmed up. The other is that
- if we specify the icon {it after/} creating the frame, we will unconditionally
- override an icon that the user may have specified with the .{-WI}
- option on the command line. (This is one of the little things a
- programmer has to turn by trial and error, since the XView documentation
- leaves much unsaid.)
- The colors used in the icon will be inherited from the frame, so they will
- be reversed if the user asks for reverse video. I~prefer to have the icon
- always in black on a yellow background, so I'm making the color explicit.
- (I hope this will work on monochrome displays; it works fine on my
- grayscale monitor.)
- @<Create a frame with the gnu icon@>=
- {@+Server_image icon_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
- XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,icon_bits,NULL);
- Server_image mask_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
- XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,mask_bits,NULL);
- Cms cms=(Cms)xv_create(NULL,CMS,CMS_SIZE,2,@|
- CMS_NAMED_COLORS,"yellow","black",NULL,NULL);
- Icon icon=(Icon)xv_create(NULL,ICON,@|
- ICON_IMAGE,icon_image,ICON_MASK_IMAGE,mask_image,@|
- WIN_CMS,cms,NULL);
- frame=xv_create(NULL,FRAME,FRAME_ICON,icon,NULL);
- }
- @ @<Include...@>=
- #include <xview/cms.h>
- @ If the user hasn't specified a label with the .{-Wl} option, we turn off
- the header line at the top of the frame. That gives us a chance to see
- two more lines of the file .{emacs} is editing. However, we add a
- label of our own; it will show up in the virtual window manager display.
- @<Remove the frame header, unless the user has specifically requested it@>=
- if (xv_get(frame,XV_LABEL)==NULL) /* no label specified */
- xv_set(frame,FRAME_SHOW_HEADER,FALSE,XV_LABEL,"OEMACS",NULL);
- @ The following icon and mask are derived from the ``what's gnu'' image on the
- back cover of the GNU Emacs manual. (This accounts for my black-on-yellow
- preference.)
- @<Global...@>=
- unsigned short icon_bits[]={@|
- 0x0000, 0x0000, 0x0000, 0x1E00,
- 0x0000, 0x0000, 0x0000, 0x0900,@|
- 0x001E, 0x0000, 0x0000, 0x0880,
- 0x0064, 0x0000, 0x0000, 0x0440,@|
- 0x0088, 0x0000, 0x0000, 0x0420,
- 0x0110, 0x0000, 0x0000, 0x0210,@|
- 0x0220, 0x0000, 0x0000, 0x0210,
- 0x0420, 0x0FCF, 0x01C0, 0x0108,@|
- 0x0840, 0x1030, 0x8620, 0x0088,
- 0x1080, 0x00C0, 0x5810, 0x0084,@|
- 0x1080, 0x1F00, 0x2008, 0x0044,
- 0x2100, 0xE200, 0x1004, 0x0044,@|
- 0x4103, 0x0400, 0x0002, 0x0042,
- 0x4204, 0x080E, 0x0001, 0x0042,@|
- 0x8200, 0x7830, 0x0020, 0x8082,
- 0x8203, 0x9040, 0x0018, 0x4102,@|
- 0x8204, 0x2080, 0x07C6, 0x3E04,
- 0x8108, 0x410C, 0x0021, 0x8004,@|
- 0x8080, 0x8210, 0x03D0, 0x6008,
- 0x4041, 0x0420, 0x0008, 0x1810,@|
- 0x403E, 0x0820, 0x0FFC, 0x0620,
- 0x2000, 0x1040, 0x0002, 0x01C0,@|
- 0x1000, 0x608C, 0x0FFF, 0x0060,
- 0x0801, 0x8110, 0x0080, 0x8118,@|
- 0x0406, 0x0220, 0x1FFF, 0x66E0,
- 0x0238, 0x044F, 0x0000, 0xD800,@|
- 0x01C0, 0x0890, 0x8FFF, 0x4000,
- 0x0300, 0x10A6, 0x4041, 0x6000,@|
- 0x1C00, 0x2026, 0x4FFF, 0x6000,
- 0x60CC, 0x4026, 0x4001, 0x6000,@|
- 0x1F33, 0x8010, 0x8FFF, 0x4000,
- 0x0012, 0x000F, 0x0040, 0xC000,@|
- 0x0022, 0x4000, 0x07FF, 0x4000,
- 0x0024, 0x4000, 0x0000, 0x2000,@|
- 0x0024, 0x4818, 0x8FFF, 0xE000,
- 0x0024, 0x4907, 0x0040, 0x2000,@|
- 0x0044, 0x4900, 0x1FFF, 0xE000,
- 0x0044, 0x4900, 0x0000, 0x2000,@|
- 0x0044, 0x4900, 0x07FF, 0xE000,
- 0x0044, 0x4880, 0x0020, 0x2000,@|
- 0x0044, 0x4880, 0x07FF, 0xE000,
- 0x0044, 0x4840, 0x0000, 0x2000,@|
- 0x0044, 0x2A20, 0x07FF, 0xE000,
- 0x0044, 0x2410, 0x0020, 0x2000,@|
- 0x0042, 0x2448, 0x0FFF, 0xE000,
- 0x0042, 0x2948, 0x0000, 0x2000,@|
- 0x0041, 0x1144, 0x07FF, 0xA000,
- 0x0041, 0x1144, 0x2010, 0x1000,@|
- 0x0021, 0x1126, 0x20FA, 0x1000,
- 0x0024, 0x8925, 0x2600, 0x1000,@|
- 0x0014, 0x8924, 0xA138, 0x7000,
- 0x0016, 0x88A4, 0x9090, 0x6000,@|
- 0x000A, 0x44A4, 0x4880, 0xA000,
- 0x0002, 0x44A2, 0x4401, 0x2000,@|
- 0x0003, 0x4492, 0x2001, 0x4000,
- 0x0001, 0x2451, 0x3002, 0x8000,@|
- 0x0000, 0xA251, 0x1E05, 0x0000,
- 0x0000, 0x2248, 0xA1F9, 0x8000,@|
- 0x0000, 0x1648, 0x9002, 0x8000,
- 0x0000, 0x1A28, 0x4C02, 0x8000,@|
- 0x0000, 0x1220, 0x43FC, 0x8000,
- 0x0000, 0x0120, 0x2000, 0x8000,@|
- 0x0000, 0x0120, 0x2003, 0x0000,
- 0x0000, 0x0150, 0x1FFC, 0x0000
- };
- unsigned short mask_bits[]={@|
- 0x0000, 0x0000, 0x0000, 0x1E00,
- 0x0000, 0x0000, 0x0000, 0x0F00,@|
- 0x001E, 0x0000, 0x0000, 0x0F80,
- 0x007C, 0x0000, 0x0000, 0x07C0,@|
- 0x00F8, 0x0000, 0x0000, 0x07E0,
- 0x01F0, 0x0000, 0x0000, 0x03F0,@|
- 0x03E0, 0x0000, 0x0000, 0x03F0,
- 0x07E0, 0x0FCF, 0x01C0, 0x01F8,@|
- 0x0FC0, 0x103F, 0x87F0, 0x00F8,
- 0x1F80, 0x00FF, 0xDFF0, 0x00FC,@|
- 0x1F80, 0x1FFF, 0xFFF8, 0x007C,
- 0x3F00, 0xE3FF, 0xFFFC, 0x007C,@|
- 0x7F03, 0x07FF, 0xFFFE, 0x007E,
- 0x7E04, 0x0FFF, 0xFFFF, 0x007E,@|
- 0xFE00, 0x7FFF, 0xFFFF, 0x80FE,
- 0xFE03, 0x9FFF, 0xFFFF, 0xC1FE,@|
- 0xFE04, 0x3FFF, 0xFFFF, 0xFFFC,
- 0xFF08, 0x7FFF, 0xFFFF, 0xFFFC,@|
- 0xFF80, 0xFFFF, 0xFFFF, 0xFFF8,
- 0x7FC1, 0xFFFF, 0xFFFF, 0xFFF0,@|
- 0x7FFF, 0xFFFF, 0xFFFF, 0xFFE0,
- 0x3FFF, 0xFFFF, 0xFFFF, 0xFFC0,@|
- 0x1FFF, 0xFFFF, 0xFFFF, 0xFFE0,
- 0x0FFF, 0xFFFF, 0xFFFF, 0xFFF8,@|
- 0x07FF, 0xFFFF, 0xFFFF, 0xFEE0,
- 0x03FF, 0xFFFF, 0xFFFF, 0xF800,@|
- 0x01FF, 0xFFFF, 0xFFFF, 0xE000,
- 0x03FF, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x1FFF, 0xFFFF, 0xFFFF, 0xE000,
- 0x7FFF, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x1F7F, 0xFFFF, 0xFFFF, 0xC000,
- 0x001F, 0xFFFF, 0xFFFF, 0xC000,@|
- 0x003F, 0xFFFF, 0xFFFF, 0xC000,
- 0x003F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x003F, 0xFFFF, 0xFFFF, 0xE000,
- 0x003F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x007F, 0xFFFF, 0xFFFF, 0xE000,
- 0x007F, 0xFFFF, 0xFFFF, 0xF000,@|
- 0x003F, 0xFFFF, 0xFFFF, 0xF000,
- 0x003F, 0xFFFF, 0xFFFF, 0xF000,@|
- 0x001F, 0xFFFF, 0xFFFF, 0xF000,
- 0x001F, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x000B, 0xFFFF, 0xFFFF, 0xE000,
- 0x0003, 0xFFFF, 0xFFFF, 0xE000,@|
- 0x0003, 0xFFFF, 0xFFFF, 0xC000,
- 0x0001, 0xFFFF, 0xFFFF, 0x8000,@|
- 0x0000, 0xBFF1, 0xFFFF, 0x0000,
- 0x0000, 0x3FF8, 0xFFFF, 0x8000,@|
- 0x0000, 0x1FF8, 0xFFFF, 0x8000,
- 0x0000, 0x1FF8, 0x7FFF, 0x8000,@|
- 0x0000, 0x13E0, 0x7FFF, 0x8000,
- 0x0000, 0x01E0, 0x3FFF, 0x8000,@|
- 0x0000, 0x01E0, 0x3FFF, 0x0000,
- 0x0000, 0x0150, 0x1FFC, 0x0000
- };
- @* Emulating a terminal.
- We will run .{emacs} in a ``tty subwindow,'' named after the teletype
- terminals of ancient yore.
- The |argv| array will be a command line that invokes
- .{emacs} with all arguments not removed by |xv_init|, i.e., all arguments
- that remain after generic XView arguments have been removed.
- We have to say |WIN_IS_CLIENT_PANE|, otherwise fonts specified on the
- command line will be ignored. (This cryptic instruction is mentioned briefly
- in the XView reference manual, but not in the XView programming manual;
- I~would never have discovered it without Jeff Peck's help.)
- We also have to set |TTY_QUIT_ON_CHILD_DEATH| to |TRUE|. Otherwise when
- .{emacs} exits (via control-X, control-C) there still will be a terminal
- window (into which we can type but not access the shell).
- Before starting .{emacs} we set the environment variable
- .{TERM} equal to .{sun}.
- This will tell .{emacs} to initialize itself with the
- programs in its source file .{lisp/term/sun.el}, where special
- adaptations for Sun-style terminals have been recorded.
- @<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 part
- and a pseudo-terminal part. (The manual does mention briefly that text
- subwindows have views---at the beginning of section 6.3, and indirectly in
- one of the examples in the chapter on color.)
- The view window of an emulated tty will receive keyboard and
- mouse events. We need to know its ``handle,'' because we want to
- modify XView's default interpretation of many of those events.
- For example, we want to grab the keyboard focus (i.e., to begin receiving
- keyboard input) as soon as the user moves the mouse into the .{emacs}
- window. The normal OpenLook default requires a user to click in the window
- first, 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 it
- more visible against a black background.
- Changing the cursor is another undocumented reason why we need to know
- about the tty's view window; nothing changes if we try to attach
- the 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 order
- to convert mouse positions into coordinates that .{emacs} will like.
- If the user has specified a font explicitly, the font will presumably have
- a fixed width for all characters; we can learn the relevant dimensions
- by calling |xv_get|. But if the user has not specified a font, the
- situation is trickier; |xv_get| will report the width of the default
- {it non/}-fixed-width font, and this will probably differ from the width of
- the 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 first
- call to |xv_create|---will therefore fail.
- Thus, we have to work around two distinct bugs in XView. The solution
- is 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 what
- font will go into the tty window. The program below works correctly
- even if the command line specifies .{-scale} .{large}, say, instead of
- specifying a new font explicitly by something like .{-font} .{9x15}.
- While we are cataloguing peculiarities of XView, we might as well mention
- that the default character dimensions of the default font (Lucida) are
- reported to be $8times13$ in the 12-point (medium) size, $8times15$ in the
- 14-point (large) size, and $12times20$ in the 19-point (extralarge) size.
- The actual character dimensions in the window come, however, from the
- default fixed-width font (Lucida typewriter), and they are $7times13$,
- $9times15$, and $11times23$ in the same three sizes. No logical progression
- is 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 right
- event mask and the right cursor, and how to calculate the sizes of the
- characters it will contain. All that remains is for us to do these
- operations in the proper order, and to specify a filter routine that
- will monitor and edit all communications between the keyboard and the
- Emacs processor in the window.
- The new ingredient is the filter specification. We tell the XView
- notifier to call |filter| when a window event occurs, instead of
- letting it call the tty subroutine event handler directly. The parameter
- |NOTIFY_SAFE| implies that the window's event handler is
- part 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 and
- either process it ourselves or pass it through (possibly modified)
- to its normal recipient. In the first case we return the code
- value |NOTIFY_DONE|, since we aren't reporting any errors;
- in the second case we call the normal event handler and return the value
- it returns to us.
- An XView event is a data structure that has been partially
- interpreted by the XView routines, which add semantic sugar to
- the complex union type of X~Window events. We need not look
- too 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 keyboard
- focus, we want to send a coded sequence of characters to .{emacs}.
- itemitem{(3)} When a key goes down, and we have the keyboard focus, we
- want to send an appropriate sequence of characters to .{emacs}.
- itemitem{(4)} When the status of the Num Lock indicator light changes, we
- will send emacs the command {tt turn-numlock-on} or {tt turn-numlock-off},
- for reasons described below.
- smallskipnoindent Other events, like instructions to repaint or
- resize 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 mouse
- enters 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 any
- semantic ``keyboard acceleration'' actions it might have been assigned
- by OpenWindows.
- We also make the Meta key add 128 here. An undocumented macro
- called |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 lots
- of useful functions when we are .{emacs}ing to the max. Besides the
- letters 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 keys
- labeled Help, Alt, AltGraph, Ins, Del, Enter, $+$, $-$, which we will
- pretend have been labeled B1--B8.
- The L5 key, also known as Front, is controlled by the Open Look
- window 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 the
- window 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 comparatively
- useless character $3over4$, 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 like
- their functions as they stand. (L5 and L7 still come through if a
- Shift, Control, and/or Meta key is down.)
- I can never remember the difference between Delete and BackSpace, so I
- have mapped them both into control-?, ASCII code 127.
- There are two Shift keys, one at the left and one at the right, which
- are best kept indistinguishable from each other. Similarly, the left
- and right Meta keys (`.{char27}') are essentially identical. There's a
- Control key too. These three types of modifier keys generate keypress
- events, but we ignore them; the only thing that matters to us is whether
- they are currently up or down, when other keys are pressed.
- fontttit=cmitt10
- There also are three special keys that do not generate events, so we
- never see them. The CapsLock key toggles the Caps Lock light and
- changes lowercase letters to uppercase when the light is on. The
- NumLock key toggles the Num Lock light and changes the interpretation
- of R4--R15 and B4--B8 when that light is on. The Compose key turns the
- Compose light on until you type two characters, then it produces a
- special symbol if those two characters match a pattern. For example,
- when Compose is followed by either .{a"} or .{"a} you get the 8-bit
- ISO 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 {ttitchar`$}
- and so on. (A list of all composition patterns
- appears in .{<X11/Suncompose.h>}, but not in any of the manuals
- I've seen.) The light goes off after two characters have been
- typed, or if your first character is not composable, or if
- you hit Compose again prematurely. If no proper two-character pattern
- was specified, only ``up'' events (key releases) are transmitted, and
- nothing will pass through to .{emacs}.
- One other feature is worth noting: The key between F12 and Delete
- produces a backslash `.\', or a vertical line `.{char125}' when
- shifted. Everybody knows that, but even more is true. If you hold the
- AltGraph key down and press this key, it turns out that you get the
- broken-bar character `{tthbox to1em{hssvbox{hrule width 1pt height
- 3ptvskip1.5pthrule height2pt depth1pt}hss}}'. This is the only key that the
- engineers 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
- combinations that are either useful or harmful.
- Once upon a time the Caps Lock key might have affected the |event_shiftmask|
- field of an event, but it has no effect now. The shiftmask is always an
- even number, contrary to the implications of .{<xview/win_input.h>}.
- @ The function keys will be translated into a four-character code.
- First comes control-X; then an asterisk; then a letter, .{a}--.{o}
- for function numbers 1--15, respectively; and then another letter,
- identifying left, right, top, or bottom. The final letter is
- ordinarily `.l', `.r', `.t', or `.b', respectively. But it is `.L', `.R',
- `.T', or `.B' if a Shift key is down. Furthermore the Control key
- subtracts 64 from the ASCII code, so you get `.,', `.2', `.4', or
- `."' with Control and no Shift. With both Control and Shift you get
- .{\C-L}, .{\C-R}, .{\C-T}, .{\C-B}. A Meta key adds another 128
- to the code. Thus, each function key leads to eight possibilities.
- For example, if F4 is pressed when Control and Shift are down, but not
- Meta, the four-letter code is .{\C-X*d\C-T}. The user could type
- that sequence of four characters and get the same effect.
- Shifted function keys sometimes have a nice mnemonic significance.
- For example, key R14, also labeled PgDn, is usually bound to the Emacs
- operation `.{scroll-up}', which moves the window down [sic] by one
- screenful; we can then bind Shift-R14 to .{forward-page}, which advances
- down to the next page boundary. In .{cweb-mode}, the next page boundary
- is the next .{@@*}, beginning a major part of the program. Similarly,
- it's convenient to bind B7, the keypad `.+' key, to .{forward-paragraph}.
- Then in .{cweb-mode}, Shift-B7 goes to the next module (the next
- .{@@ } or .{@@*}).
- A Composed character will be preceded by .{\C-Q}, the Emacs `quote'
- character, to distinguish it from a character that was generated with the
- Meta key down. This also applies to the broken-bar character, which
- will incidentally be preceded by AltGraph, which is B3; you'll probably
- want to bind B3 to a no-op if broken bars are important to you.
- @ This program assumes that several key codes have been rebound from
- their normal values. Namely, the commands
- $$vbox{halign{.{#}hfilcr
- keysym R2 = threequarterscr
- keysym KP_Subtract = onehalfcr
- keysym KP_Add = onequartercr
- keysym KP_Enter = threesuperiorcr
- keysym KP_Decimal = twosuperiorcr
- keysym KP_0 = onesuperiorcr}}$$
- should be executed by .{xmodmap}, preferably in the user's .{.xinitrc} file.
- This makes the keys act as $3over4$, $1over2$, $1over4$, $^3$, $^2$, and
- $^1$, respectively. The corresponding 8-bit codes are respectively
- 190, 189, 188, 179, 178, 185. (By the way, can anybody explain why the ISO
- LATIN-1 code has $^0$, $^2$, and $^3$ in the positions of meta-0, meta-2,
- and meta-3, while $^1$ is in the position of meta-9?)
- @.xmodmap@>
- We haven't actually bound the keys this way to use them in editing.
- We did it to provide linguistically unimportant codes that OpenWindows
- wouldn't mess up; its normal conventions make those valuable keys
- unusable for editing, except as duplicates for other existing keys.
- We send .{turn-numlock-on/off} commands so that .{emacs} can keep in
- synch with the keyboard state. Namely, it will rebind the function
- keys B4--B8 to their numeric-keypad equivalents while the Num Lock light is on.
- On the other hand, our remapping does make the Num Lock
- feature useless in other (non-Emacs) applications. If you don't
- rebind the keys as stated, you lose the functionality of R2 and B4--B8,
- but .{oemacs} will still work.
- The Help key is another special case. We don't want to remap it,
- because it gives useful help information with other OpenWindows
- applications. If Help is pressed without the shift or control key,
- the |event_id| is zero and the |event_action| is |ACTION_HELP|.
- Control-Help is similar, but with |ACTION_TEXT_HELP|. Shift-Help is
- more complicated; it invokes `helpopen: starting new Viewer', after
- generating an event that has |event_action=WIN_VISIBILITY_NOTIFY|. The
- program below considers the Help key B1 to be characterized by any
- event with |event_id=0| and either |event_action!=0| or
- |event_shiftmask!=CTRLMASK|.
- @<Translate a function key into a special escape sequence@>=
- {@+register int bank='b'; /* |'l'|, |'r'|, |'t'|, or |'b'| */
- register int n; /* function key serial number, |1<=n<=15| */
- if (id>=KEY_LEFT(1)) @<Translate an ordinary function key@>@;
- else if (id>=256) @<Look for Alt or AltGraph@>@;
- else if (id>=128)
- @<Translate a special function key or composed character@>@;
- else if (id>0 ||
- (event_action(event)==0 && event_shiftmask(event)==CTRLMASK))
- goto non_function;
- else n=1; /* Help key */
- emit_function_key:@<Emit the code for a function key and |return|@>;
- non_function:;
- }
- @ I'm assuming here that the event id codes occur in the order left, right,
- top, bottom, and that no higher event codes exist.
- @<Translate an ordinary function key@>=
- {
- if (id<KEY_RIGHT(1)) { /* on the left bank */
- bank='l';@+n=id-KEY_LEFT(0);
- } else if (id<KEY_TOP(1)) { /* on the right bank */
- bank='r';@+n=id-KEY_RIGHT(0);
- } else if (id<KEY_BOTTOM(1)) {
- bank='t';@+n=id-KEY_TOP(0);
- } else n=id-KEY_BOTTOM(0);
- goto emit_function_key;
- }
- @ The event codes examined here appear in .{<xview/win_event.h>}
- but not in the XView reference manual.
- @<Look for Alt or AltGraph@>=
- if (id==SHIFT_ALT) {
- n=2;@+goto emit_function_key;
- } else if (id==SHIFT_ALTG) {
- n=3;@+goto emit_function_key;
- } else goto non_function;
- @ The |ttysw_input| routine sends text to a tty's view window.
- The second parameter is a string, not necessarily terminated by
- |' '| or anything else; the third parameter is the string length.
- @<Emit the code for a function key and |return|@>=
- {
- if (event_shift_is_down(event)) bank-=32;
- if (event_ctrl_is_down(event)) bank-=64;
- if (event_meta_is_down(event)) bank+=128;
- buf[2]=n+'a'-1;
- buf[3]=bank;
- ttysw_input(window,buf,4);
- return NOTIFY_DONE;
- }
- @ @<Global...@>=
- char buf[]="