Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!princeton!orsvax1!pyrnj!caip!lll-crg!mordor!ut-sally!ut-ngp!mic From: mic@ut-ngp.UUCP (Mic Kaczmarczik) Newsgroups: net.micro.amiga Subject: Amiga terminal driver for MicroEmacs (3 of 3) Message-ID: <3277@ut-ngp.UUCP> Date: Wed, 23-Apr-86 11:31:21 EST Article-I.D.: ut-ngp.3277 Posted: Wed Apr 23 11:31:21 1986 Date-Received: Sat, 26-Apr-86 05:18:22 EST Reply-To: mic@ut-ngp.UUCP (Mic Kaczmarczik) Organization: U. Texas Computation Ctr Lines: 1779 This file is part 3 of 3 the MicroEmacs Amiga code. It contains the Intuition version of the terminal driver. Mic Kaczmarczik ...!ihnp4!seismo!ut-sally!ut-ngp!mic mic@a20.cc.utexas.edu ---------------------------------CUT HERE------------------------------------- -h- console.c Wed Apr 23 08:53:04 1986 console.c /* * These functions are taken directly from the * console.device chapter in the Amiga V1.1 * ROM Kernel Manual. */ #include #include #include #include #include extern LONG OpenDevice(); extern LONG DoIO(); extern LONG SendIO(); /* * Open a console device, given a read request * and a write request message. */ int OpenConsole(writerequest,readrequest,window) struct IOStdReq *writerequest; struct IOStdReq *readrequest; struct Window *window; { LONG error; writerequest->io_Data = (APTR) window; writerequest->io_Length = (ULONG) sizeof(*window); error = OpenDevice("console.device", 0L, writerequest, 0L); /* clone required parts of the request */ readrequest->io_Device = writerequest->io_Device; readrequest->io_Unit = writerequest->io_Unit; return((int) error); } /* * Output a single character * to a specified console */ int ConPutChar(request,character) struct IOStdReq *request; char character; { request->io_Command = CMD_WRITE; request->io_Data = (APTR)&character; request->io_Length = (ULONG)1; DoIO(request); /* caution: read comments in manual! */ return(0); } /* * Output a NULL-terminated string of * characters to a console */ int ConPutStr(request,string) struct IOStdReq *request; char *string; { request->io_Command = CMD_WRITE; request->io_Data = (APTR)string; request->io_Length = (LONG)-1; DoIO(request); return(0); } /* * Write out a string of predetermined * length to the console */ int ConWrite(request,string,len) struct IOStdReq *request; char *string; int len; { request->io_Command = CMD_WRITE; request->io_Data = (APTR)string; request->io_Length = (LONG)len; DoIO(request); return(0); } /* * Queue up a read request * to a console */ int QueueRead(request,whereto) struct IOStdReq *request; char *whereto; { request->io_Command = CMD_READ; request->io_Data = (APTR)whereto; request->io_Length = (LONG)1; SendIO(request); return(0); } -h- menu.c Wed Apr 23 08:53:04 1986 menu.c /* * Dynamic Intuition menu functions * from the author of PDTerm */ #include "exec/types.h" #include "exec/memory.h" #include "graphics/text.h" #include "intuition/intuition.h" #define MEMFLAGS (LONG) (MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR) extern char *AllocMem(); extern LONG FreeMem(); /* * Create an instance of an Intuitext structure * containing text, positioned at (left,top) */ struct IntuiText *NewIText(text, left, top) char *text; int left, top; { struct IntuiText *newtext = NULL; newtext = (struct IntuiText *) AllocMem((LONG) sizeof(*newtext), MEMFLAGS); newtext->IText = (UBYTE *)text; newtext->FrontPen = 0; newtext->BackPen = 1; newtext->DrawMode = JAM2; newtext->LeftEdge = left; newtext->TopEdge = top; newtext->ITextFont = NULL; newtext->NextText = NULL; return(newtext); } /* * Add an Intuitext structure to the end of * list of them, returning a pointer to the * new Intuitext. */ struct IntuiText *AddIText(IText, text) struct IntuiText *IText; char *text; { struct IntuiText *newtext = NULL; newtext = (struct IntuiText *) AllocMem((LONG) sizeof(*newtext), MEMFLAGS); newtext->IText = (UBYTE *)text; newtext->FrontPen = IText->FrontPen; newtext->BackPen = IText->BackPen; newtext->DrawMode = IText->DrawMode; newtext->LeftEdge = IText->LeftEdge; newtext->TopEdge = IText->TopEdge + 11; newtext->ITextFont = IText->ITextFont; newtext->NextText = NULL; IText->NextText = newtext; return(newtext); } /* * Dispose of a lise of IntuiText structures */ DisposeIText(IText) struct IntuiText *IText; { struct IntuiText *cur, *next; cur = IText; for(next = cur->NextText; cur != NULL; next = next->NextText) { FreeMem(cur,(LONG) sizeof(*cur)); cur = next; } } /* * Dynamic menu constructor functions */ #define InterMenuWidth 15 /* * Create a new menu structure. */ struct Menu *NewMenu(menuname, width, height) char *menuname; int width, height; { struct Menu *menu = NULL; menu = (struct Menu *) AllocMem((LONG) sizeof(*menu), MEMFLAGS); menu->NextMenu = NULL; menu->LeftEdge = 0; menu->TopEdge = 0; menu->Width = width; menu->Height = height; menu->Flags = MENUENABLED; menu->MenuName = menuname; menu->FirstItem = NULL; return(menu); } /* * Create a new menu and add it to * the end of the list of menus. */ struct Menu *AddMenu(menus, MenuName, width, height) struct Menu *menus; char *MenuName; int width, height; { struct Menu *newmenu; newmenu = NewMenu(MenuName, width, height); newmenu->LeftEdge = menus->LeftEdge + menus->Width + InterMenuWidth; menus->NextMenu = newmenu; return(newmenu); } /* * Create a new menu item */ struct MenuItem *NewMenuItem(name, width, height) char *name; int width, height; { struct MenuItem *newitem = NULL; struct IntuiText *NewIText(), *newtext = NULL; newitem = (struct MenuItem *) AllocMem((LONG) sizeof(*newitem), MEMFLAGS); newtext = NewIText(name,0,1); newitem->NextItem = NULL; newitem->ItemFill = (APTR) newtext; newitem->LeftEdge = 0; newitem->TopEdge = 0; newitem->Width = width; newitem->Height = height; newitem->Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP; newitem->MutualExclude = 0; newitem->SelectFill = NULL; newitem->Command = 0; newitem->SubItem = NULL; newitem->NextSelect = 0; return(newitem); } /* * Start the menu item list for a menu. */ struct MenuItem *AddNewMenuItem(menu, name, width, height) struct Menu *menu; char *name; int width, height; { struct MenuItem *newitem, *NewMenuItem(); newitem = NewMenuItem(name, width, height); menu->FirstItem = newitem; return(newitem); } /* * Add to a menu item list */ struct MenuItem *AddItem(items, name) struct MenuItem *items; char *name; { struct MenuItem *newitem, *NewMenuItem(); newitem = NewMenuItem(name, items->Width, items->Height); newitem->TopEdge = items->TopEdge + items->Height; newitem->LeftEdge = items->LeftEdge; items->NextItem = newitem; return(newitem); } /* * Start a list of subitems for a menu item. */ struct MenuItem *AddNewSubItem(item, name, width, height) struct MenuItem *item; char *name; int width, height; { struct MenuItem *newitem, *NewMenuItem(); newitem = NewMenuItem(name, width, height); item->SubItem = newitem; newitem->LeftEdge = item->Width; return(newitem); } /* * Dispose of a menu item. */ DisposeItem(item) struct MenuItem *item; { DisposeIText((struct ItuiText *)item->ItemFill); FreeMem(item,(LONG) sizeof(*item)); } /* * Dispose of a list of menu items. */ DisposeItems(items) struct MenuItem *items; { struct MenuItem *cur, *next; cur = items; for(next = cur->NextItem; cur != NULL; next = next->NextItem){ DisposeItem(cur); cur = next; } } /* * Dispose of a single menu */ DisposeMenu(menu) struct Menu *menu; { DisposeItems(menu->FirstItem); FreeMem(menu,(LONG) sizeof(*menu)); } /* * Get rid of a menu list. */ DisposeMenus(menus) struct Menu *menus; { struct Menu *cur, *next; cur = menus; for(next = cur->NextMenu; cur != NULL; next = next->NextMenu){ DisposeMenu(cur); cur = next; } } -h- tty.c Wed Apr 23 08:53:04 1986 tty.c /* * Name: MicroEMACS * Amiga console device virtual terminal display * Version: 31 * Last Edit: 19-Apr-86 * Created: 19-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * * Drives the Amiga console device display. The code is a combination * of the Heath and ANSI terminal drivers. */ #include "def.h" #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ extern int ttrow; extern int ttcol; extern int tttop; extern int ttbot; extern int tthue; int tceeol = 3; /* Costs, ANSI display. */ int tcinsl = 17; int tcdell = 16; /* * Initialize the terminal when the editor * gets started up. This is a no-op on the Amiga. */ ttinit() { } /* * Clean up the terminal, in anticipation of * a return to the command interpreter. This is a no-op * on the Amiga. */ tttidy() { } /* * Move the cursor to the specified * origin 0 row and column position. Try to * optimize out extra moves; redisplay may * have left the cursor in the right * location last time! */ ttmove(row, col) { if (ttrow!=row || ttcol!=col) { ttputc(ESC); ttputc('['); asciiparm(row+1); ttputc(';'); asciiparm(col+1); ttputc('H'); ttrow = row; ttcol = col; } } /* * Erase to end of line. */ tteeol() { ttputc(ESC); ttputc('['); ttputc('K'); } /* * Erase to end of page. */ tteeop() { ttputc(ESC); ttputc('['); ttputc('J'); } /* * Make a noise. */ ttbeep() { ttputc(BEL); ttflush(); } /* * Convert a number to decimal * ascii, and write it out. Used to * deal with numeric arguments. */ asciiparm(n) register int n; { register int q; q = n/10; if (q != 0) asciiparm(q); ttputc((n%10) + '0'); } /* * Insert a block of blank lines onto the * screen, using a scrolling region that starts at row * "row" and extends down to row "bot". Deal with the one * line case, which is a little bit special, with special * case code. * Since we don't really have a scrolling region, * delete the block of lines that would have been deleted if * we'd had one, then insert blank lines to move the rest * of the screen back to where it belongs. This idea from * the Heath driver. */ ttinsl(row, bot, nchunk) { register int i; if (row == bot) { /* Funny case. */ if (nchunk != 1) abort(); ttmove(row, 0); tteeol(); return; } ttmove(1+bot-nchunk, 0); if (nchunk > 0) { /* Delete a chunk of lines */ ttputc(ESC); /* nchunk in size. Rest of */ ttputc('['); /* screen moves up. */ asciiparm(nchunk); ttputc('M'); } ttmove(row, 0); if (nchunk > 0) { /* Insert a chunk nchunk in size*/ ttputc(ESC); /* before current line, sliding */ ttputc('['); /* rest of screen down. */ asciiparm(nchunk); ttputc('L'); } ttrow = row; /* End up on current line */ ttcol = 0; } /* * Delete a block of lines, with the uppermost * line at row "row", in a screen slice that extends to * row "bot". The "nchunk" is the number of lines that have * to be deleted. This is done by deleting nchunk lines at the * appropriate spot, then inserting nchunk lines to make up for * the empty space at the bottom of the virtual scrolling region. */ ttdell(row, bot, nchunk) { register int i; if (row == bot) { /* One line special case */ ttmove(row, 0); tteeol(); return; } if (nchunk > 0) { ttmove(row, 0); ttputc(ESC); ttputc('['); asciiparm(nchunk); ttputc('M'); } ttmove(1+bot-nchunk,0); if (nchunk > 0) { ttputc(ESC); /* For all lines in chunk */ ttputc('['); /* INS line before bottom */ asciiparm(nchunk); /* Bottom of window (and rest */ ttputc('L'); /* of screen) moves down */ } ttrow = HUGE; ttcol = HUGE; ttmove(bot-nchunk,0); } /* * No-op. */ ttwindow(top,bot) { } /* * No-op. */ ttnowindow() { } /* * Set the current writing color to the * specified color. Watch for color changes that are * not going to do anything (the color is already right) * and don't send anything to the display. */ ttcolor(color) register int color; { if (color != tthue) { if (color == CTEXT) { /* Normal video. */ ttputc(ESC); ttputc('['); ttputc('m'); } else if (color == CMODE) { /* Reverse video. */ ttputc(ESC); ttputc('['); ttputc('7'); ttputc('m'); } tthue = color; /* Save the color. */ } } /* * This routine is called by the * "refresh the screen" command to try and resize * the display. The new size, which must be deadstopped * to not exceed the NROW and NCOL limits, is stored * back into "nrow" and "ncol". Display can always deal * with a screen NROW by NCOL. Look in "window.c" to * see how the caller deals with a change. */ #define CSI 0x9B extern int ttsize(); /* Defined by "ttyio.c" */ ttresize() { int newnrow, newncol; ttsize(&newnrow,&newncol); /* ask tty how big it is */ if (newnrow < 1) /* check limits. */ newnrow = 1; else if (newnrow > NROW) newnrow = NROW; if (newncol < 1) newncol = 1; else if (newncol > NCOL) newncol = NCOL; nrow = newnrow; ncol = newncol; } /* * Read an unsigned parameter from the console */ static readparm(delim) char delim; { register int parm; register int c; parm = 0; while ((c=ttgetc()) >= '0' && c <= '9') parm = 10 * parm + c - '0'; return (c == delim) ? parm : -1; } -h- ttydef.h Wed Apr 23 08:53:04 1986 ttydef.h /* * Name: MicroEMACS * Amiga console device virtual terminal header file * Version: 31 * Last edit: 20-Apr-86 * Created: 20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * Add Intuition menu support * */ #define GOSLING 1 /* Compile in fancy display. */ #define MEMMAP 0 /* Not memory mapped video. */ #define NROW 23 /* Rows. */ #define NCOL 77 /* Columns (AmigaDOS) */ /* * Special keys for the default Amiga console device keymap. * Function key codes are in the form v~ * where v is a 1 or 2-digit code between 0 and 19, * so they comprise the first 20 entries in the key * table. The next 12 entries are for the help and * arrow keys. There is no shifted value for the * HELP key. */ #define KF1 K01 #define KF2 K02 #define KF3 K03 #define KF4 K04 #define KF5 K05 #define KF6 K06 #define KF7 K07 #define KF8 K08 #define KF9 K09 #define KF10 K0A #define KSF1 K0B #define KSF2 K0C #define KSF3 K0D #define KSF4 K0E #define KSF5 K0F #define KSF6 K10 #define KSF7 K11 #define KSF8 K12 #define KSF9 K13 #define KSF10 K14 #define KUP K15 #define KSUP K16 #define KDOWN K17 #define KSDOWN K18 #define KLEFT K19 #define KSLEFT K1A #define KRIGHT K1B #define KSRIGHT K1C #define KHELP K1D /* The 'menu' key doesn't really appear on the * Amiga keyboard. When ttgetc() sees a menu * event, it saves the menu number and item, * then stuffs the sequence for KMENU into * the input buffer. */ #define KMENU K1E /* * Similarly, this is the way we shoehorn the * mouse into the input stream, using the last * function key value for this purpose. */ #define KMOUSE K1F /* * Intuition menu interface. Each set of menu items * kept in a table of MenuBinding structures, which * is in turn kept in a table of MenuInfo structures. * * These tables are indexed via the menu and item * numbers to find the internal extended name of * the function associated with a certain item. */ struct MenuBinding { char *Command; char *Binding; }; struct MenuInfo { char *Name; /* name of menu */ short NumItems; /* # of items */ short MenuWidth; /* width, in CHARACTERS */ struct MenuBinding *Items; /* item name, internal binding */ }; #define NITEMS(arr) (sizeof(arr) / (sizeof(arr[0]))) -h- ttyio.c Wed Apr 23 08:53:04 1986 ttyio.c /* * Name: MicroEmacs * Amiga terminal-dependent I/O (Intuition) * Strategy and much code borrowed from the Lattice C * example in the ROM Kernel manual. * Version: 31 * Last edit: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * Created: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic */ /* * Lots of includes. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef TRUE #undef FALSE #include "def.h" #include "sysdef.h" /* * External functions. Declared explicitly * to avoid problems with different compilers. */ extern char *OpenLibrary(); extern int OpenConsole(); extern struct Window *OpenWindow(); extern struct MsgPort *CreatePort(); extern struct IOStdReq *CreateStdIO(); extern struct Menu *InitEmacsMenu(); extern struct IntuiMessage *GetMsg(); extern LONG AbortIO(); extern LONG CloseDevice(); extern LONG ReplyMsg(); extern LONG SetMenuStrip(); extern LONG Wait(); /* * Terminal I/O global variables */ #define NIBUF 128 /* Probably excessive. */ #define NOBUF 512 /* Not too big for 750/730. */ unsigned char obuf[NOBUF]; /* Output buffer */ int nobuf; /* # of bytes in above */ unsigned char ibuf[NIBUF]; /* Input buffer */ int ibufo, nibuf; /* head, # of bytes in ibuf */ int nrow; /* Terminal size, rows. */ int ncol; /* Terminal size, columns. */ extern char *version[]; /* Version information */ /* (I cheat and use it for */ /* the window title) */ /* * Intuition global variables */ #define WINDOWGADGETS (WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE) struct NewWindow MicroEMACS = { 0, 0, /* start position */ 640, 200, /* width, height */ 0, 1, /* detail pen, block pen */ MENUPICK | CLOSEWINDOW | /* IDCMP flags */ MOUSEBUTTONS | NEWSIZE, WINDOWGADGETS | ACTIVATE, /* window flags */ NULL, /* pointer to first user gadget */ NULL, /* pointer to user checkmark */ NULL, /* title (filled in later) */ NULL, /* pointer to screen (none) */ NULL, /* pointer to superbitmap */ 360,99,639,199, /* sizing limits min and max */ WBENCHSCREEN /* screen in which to open */ }; struct IntuitionBase *IntuitionBase; /* library bases */ struct GfxBase *GfxBase; struct Window *EmacsWindow; /* Our window */ struct Menu *EmacsMenu; /* Our menu */ struct MsgPort *consoleWritePort; /* I/O ports */ struct MsgPort *consoleReadPort; int intuitionMsgBit, /* Signal bits */ consoleMsgBit; struct IOStdReq *consoleWriteMsg; /* I/O messages */ struct IOStdReq *consoleReadMsg; unsigned char letter; /* Console input buffer */ USHORT class, /* Intuition event */ code, /* information */ qualifier; APTR address; SHORT x, y; /* * Some definitions */ #define INTUITION_MESSAGE ((LONG) 1 << intuitionMsgBit) #define CONSOLE_MESSAGE ((LONG) 1 << consoleMsgBit) /* * Open up the virtual terminal MicroEMACS communicates with. * Set up the window, console, and menu strip. */ extern int Enable_Abort; /* Do NOT allow abort! */ ttopen() { Enable_Abort = 0; /* Disable ^C */ GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", (LONG) 0); if (GfxBase == NULL) /* Graphics lib */ cleanup(1); IntuitionBase = (struct IntuitionBase *) /* Intuition */ OpenLibrary("intuition.library", (LONG) 0); if (IntuitionBase == NULL) cleanup(2); /* Create our window */ MicroEMACS.Title = (UBYTE *) version[0]; EmacsWindow = OpenWindow(&MicroEMACS); if (EmacsWindow == NULL) cleanup(2); /* Ports for reading and writing */ consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0); if (consoleWritePort == NULL) cleanup(5); consoleWriteMsg = CreateStdIO(consoleWritePort); if (consoleWriteMsg == NULL) cleanup(6); consoleReadPort = CreatePort("Emacs.con.read",(LONG) 0); if (consoleReadPort == NULL) cleanup(7); consoleReadMsg = CreateStdIO(consoleReadPort); if (consoleReadMsg == NULL) cleanup(8); /* attach the console device to our window */ if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmacsWindow) != 0) cleanup(10); /* attach a menu strip to the window */ EmacsMenu = InitEmacsMenu(); SetMenuStrip(EmacsWindow, EmacsMenu); /* determine signal bit #'s */ intuitionMsgBit = EmacsWindow->UserPort->mp_SigBit; consoleMsgBit = consoleReadPort->mp_SigBit; /* initialize console read and input buffer */ QueueRead(consoleReadMsg,&letter); nibuf = ibufo = 0; /* Determine initial size of virtual terminal. */ ttsize(&nrow,&ncol); return (0); } /* * Close the virtual terminal, de-allocating * everything we have allocated. */ ttclose() { ttflush(); AbortIO(consoleReadMsg); CloseDevice(consoleWriteMsg); cleanup(0); Enable_Abort = 1; } /* * Write a single character to the screen. * Buffered for extra speed, so ttflush() * does all the work. */ ttputc(c) unsigned char c; { obuf[nobuf++] = c; if (nobuf >= NOBUF) ttflush(); } /* * Flush characters from the output buffer. * Just blast it out with a console write call. */ ttflush() { if (nobuf > 0) { ConWrite(consoleWriteMsg, obuf, nobuf); nobuf = 0; } } /* * Input buffer management. * * The input buffer is a circular queue of characters * that is updated and manipulated by the macros and * functions below. This allows multiple Intuition * events (menus, console input, etc.) to be buffered * up until Emacs asks for them. */ #define CharsBuffered() (nibuf > 0 ) #define TypeInChar(c) if (nibuf < (NIBUF - 1))\ ibuf[(ibufo + nibuf++) % NIBUF] = c; /* * Return the next character in the input buffer. */ static GetInputChar() { unsigned char ch; if (nibuf <= 0) /* this shouldn't happen. */ return 0; ch = ibuf[ibufo++]; ibufo %= NIBUF; nibuf--; return (int) ch; } /* * Get a character for Emacs, without echo or * translation. Basically, handle Intuition * events until we get one that signifies * a character was typed in some way. */ ttgetc() { register struct IntuiMessage *message; /* IDCMP message */ register LONG wakeupmask; register int charfound; /* have we got a character yet? */ if (CharsBuffered()) /* check input buffer */ return GetInputChar(); /* return immediately have one */ charfound = FALSE; do { wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE); if (wakeupmask & CONSOLE_MESSAGE) { /* Keyboard */ GetMsg(consoleReadPort); /* free message */ TypeInChar(letter); /* do this FIRST */ QueueRead(consoleReadMsg, &letter); charfound = TRUE; } if (wakeupmask & INTUITION_MESSAGE) { /* Intuition */ while(message = GetMsg(EmacsWindow->UserPort)) { class = message->Class; code = message->Code; qualifier = message->Qualifier; address = message->IAddress; x = message->MouseX; y = message->MouseY; ReplyMsg(message); /* Need ||= here because next event may */ /* not result in a character... */ charfound = charfound || HandleEvent(); } /* while (GetMsg()) */ } /* if Intuition event */ } while (charfound == FALSE); return GetInputChar(); /* finally got a character. */ } /* * Handle the events we handle... * The result indicates if we've * put a character in the input buffer. * All the event information is global, * because there's a lot of it... */ extern int quit(); /* Defined by "main.c" */ static HandleEvent() { switch(class) { case MENUPICK: /* fake the menu key */ if (code != MENUNULL) return (DoMenu()); else return (FALSE); /* No character found */ break; case MOUSEBUTTONS: /* fake the mouse key */ return (DoMouse()); break; case CLOSEWINDOW: /* Call quit() directly */ quit(FALSE, 1, KRANDOM); /* This loses if in a */ return (FALSE); /* dialogue... */ break; } return(FALSE); /* No char found */ } /* * Handle a menu selection by hand-crafting * an escape sequence that looks like a function * key to the terminal driver. Save the * menu number and item number until the * menu execution function can ask for it. */ int LastMenuNum; /* Menu number for KMENU `key' */ int LastItemNum; /* Menu item for KMENU `key' */ int LastSubItem; /* Subitem number (for completeness) */ #define CSI 0x9b /* Amiga command sequence introducer */ static DoMenu() { struct MenuItem *item, *ItemAddress(); while (code != MENUNULL) { item = ItemAddress(EmacsMenu,(LONG) code); LastMenuNum = MENUNUM(code); /* number of menu */ LastItemNum = ITEMNUM(code); /* item number */ LastSubItem = SUBNUM(code); /* subitem code */ code = item->NextSelect; } TypeInChar(CSI); /* fake the MENU key */ TypeInChar('M'); TypeInChar('~'); return (TRUE); /* found a character! */ } /* * Return the last menu selection numbers to * the caller. Used by "ttymenu.c". */ ttmenu(menu,item,subitem) int *menu, *item, *subitem; { *menu = LastMenuNum; *item = LastItemNum; *subitem = LastSubItem; LastMenuNum = (USHORT)-1; /* Forget the values */ LastItemNum = (USHORT)-1; /* so they don't get re-used */ LastSubItem = (USHORT)-1; } /* * Handle a mouse selection by inserting * a "MOUSE key" (teer) sequence into the * input buffer and saving the x, y and * qualifier values for later. */ SHORT LastMouseX, LastMouseY; /* Position of mouse */ USHORT LastQualifier; /* Qualifier (shift key?) */ static DoMouse() { /* Save last mouse position */ if (code != SELECTDOWN) return (FALSE); LastMouseX = x - EmacsWindow->BorderLeft; LastMouseY = y - EmacsWindow->BorderTop; LastQualifier = qualifier; TypeInChar(CSI); /* fake the MOUSE key */ TypeInChar('P'); /* P for Pointer */ TypeInChar('~'); return (TRUE); /* found a character! */ } /* * Return the last mouse click values to * the caller. X and Y are translated * so that (0,0) is at the edge of the * top and left borders. Used by "ttymouse.c". */ ttmouse(x,y,qualifier) SHORT *x, *y; USHORT *qualifier; { *x = LastMouseX; *y = LastMouseY; *qualifier = LastQualifier; LastMouseX = (SHORT)-1; LastMouseY = (SHORT)-1; LastQualifier = (USHORT)-1; } /* * Return the current size of the virtual * terminal to the caller. Placed in * ttyio.c because it uses information * that is only available to the virtual * terminal handler. * * Assumes the WorkBench screen default * font is TOPAZ_EIGHTY (8 wide by 8 high). */ ttsize(rows,cols) int *rows, *cols; { *rows = (EmacsWindow->Height - /* have to take borders */ EmacsWindow->BorderTop - /* into account. */ EmacsWindow->BorderBottom) / 8; *cols = (EmacsWindow->Width - EmacsWindow->BorderLeft - EmacsWindow->BorderRight) / 8; } /* * Clean up. * Fall through all the possible cases (0 means * get rid of everything and start with the case * that fits the error situation. */ extern LONG ClearMenuStrip(); extern LONG DeleteStdIO(); extern LONG DeletePort(); extern LONG CloseWindow(); extern LONG CloseLibrary(); static cleanup(prob) { switch (prob) { case 0: ClearMenuStrip(EmacsWindow); DisposeMenus(EmacsMenu); case 10: case 8: DeleteStdIO(consoleReadMsg); case 7: DeletePort(consoleReadPort); case 6: DeleteStdIO(consoleWriteMsg); case 5: DeletePort(consoleWritePort); case 4: CloseWindow(EmacsWindow); case 2: if (GfxBase != NULL) CloseLibrary(GfxBase); case 1: if (IntuitionBase != NULL) CloseLibrary(IntuitionBase); break; } return(0); } -h- ttykbd.c Wed Apr 23 08:53:04 1986 ttykbd.c /* * Name: MicroEMACS * Amiga virtual terminal keyboard, default console keymap. * Version: 31 * Last edit: 20-Apr-86 * Created: 19-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * Supports all the default console device * (RAW:) input codes for the Amiga keyboard. * Modified: 20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * [UT-14] Added processing for GR_to_META, so * characters in the alternate character set * can automatically map to META characters. * This is a rather nice thing to have... * Added KMENU to key definitions, bound to amigamenu(). * This goes with the Intuition terminal driver. */ #include "def.h" #define ESC 0x1B /* Escape, arrows et al. */ #define CSI 0x9B /* Amiga CSI */ /* * The function keys on the Amiga send back * escape sequences of the form [code~, where code * is a one or two-character code for the key. To make * it easier to decode, we place the internal key values * for these codes in this table. */ short consolemap[] = { KF1, KF2, KF3, KF4, KF5, KF6, KF7, KF8, KF9, KF10, KSF1, KSF2, KSF3, KSF4, KSF5, KSF6, KSF7, KSF8, KSF9, KSF10 }; #define NFUNCKEYS ((sizeof consolemap)/(sizeof consolemap[0])) /* * Names for the keys with basic keycode * between KFIRST and KLAST (inclusive). This is used by * the key name routine in "kbd.c". KFIRST is KRANDOM, which * we don't bind anything useful to. "Amiga Menus" is * special; we implement menus as another function key, * but there isn't really any "MENU" key on the keyboard. */ char *keystrings[] = { NULL, "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Shift-F1", "Shift-F2", "Shift-F3", "Shift-F4", "Shift-F5", "Shift-F6", "Shift-F7", "Shift-F8", "Shift-F9", "Shift-F10", "Up", "Shift-Up", "Down", "Shift-Down", "Left", "Shift-Left", "Right", "Shift-Right", "Help", "The Menu", "The Mouse" }; /* * Read in a key, doing the low level mapping * of ASCII code to 11 bit code. This level deals with * mapping the special keys into their spots in the C1 * control area. The C0 controls go right through, and * get remapped by "getkey". * * If GR_to_META is TRUE, characters in the Amiga alternate * character set get mapped to META characters. If FALSE, * they get sent straight through. */ extern int GR_to_META; /* defined in "kbd.c" */ getkbd() { register int c; register int n; loop: c = ttgetc(); if (c == CSI) { c = ttgetc(); if (c == 'P') { /* mouse sequence */ ttgetc(); /* First because it's */ return (KMOUSE); /* used a lot. */ } if (c == 'M') { /* (fake) menu key */ ttgetc(); /* discard '~' */ return (KMENU); } /* Arrow keys */ if (c == 'A') return (KUP); if (c == 'B') return (KDOWN); if (c == 'C') return (KRIGHT); if (c == 'D') return (KLEFT); if (c == 'T') return (KSUP); if (c == 'S') return (KSDOWN); if (c == '?') { /* HELP key */ ttgetc(); /* discard '~' */ return (KHELP); } /* Shifted left, right arrow */ if (c == ' ') { c = ttgetc(); if (c == 'A' || c == '@') return (c == 'A') ? (KSLEFT) : (KSRIGHT); goto loop; /* try again, sucker */ } /* Function keys */ if (c >= '0' && c <= '9') { n = 0; do { n = 10*n + c - '0'; c = ttgetc(); } while (c>='0' && c<='9'); if (c == '~' && n < NFUNCKEYS) { c = consolemap[n]; if (c != KRANDOM) return (c); goto loop; } else goto loop; /* Try again */ } goto loop; /* Try again */ } /* Meta keys -- also check for high bit set */ if ((c == ESC) || (GR_to_META && (c & 0x80))) { if (c == ESC) c = ttgetc(); c &= 0x7F; /* Strip high bit */ if (ISLOWER(c) != FALSE) /* Copy the standard */ c = TOUPPER(c); /* META code. */ if (c>=0x00 && c<=0x1F) c = KCTRL | (c+'@'); return (KMETA | c); } return (c); } /* * Terminal specific keymap initialization. * Attach the special keys to the appropriate built * in functions. Bind all of the assigned graphics in the * Amiga alternate character set to self-insert. * * Bind the fake KMENU code to amigamenu() to do * menu selection as transparently as possible. * Ditto with KMOUSE. As is the case of all the * keymap routines, errors are very fatal. */ extern int amigamenu(); /* Defined by "ttymenu.c" */ extern int amigamouse(); /* Defined by "ttymouse.c" */ ttykeymapinit() { register SYMBOL *sp; register int i; /* ADD these bindings instead of duplicating it */ keyadd(KMENU, amigamenu, "amiga-menu"); keyadd(KMOUSE, amigamouse, "amiga-mouse"); keydup(KUP, "back-line"); keydup(KDOWN, "forw-line"); keydup(KRIGHT, "forw-char"); keydup(KLEFT, "back-char"); keydup(KHELP, "help"); keydup(KSUP, "goto-bop"); keydup(KSDOWN, "goto-eop"); keydup(KSRIGHT, "forw-word"); keydup(KSLEFT, "back-word"); keydup(KF1, "down-window"); keydup(KF2, "forw-page"); keydup(KF3, "enlarge-window"); keydup(KF4, "forw-window"); keydup(KF5, "split-window"); keydup(KF6, "file-visit"); keydup(KF7, "file-save"); keydup(KF8, "start-macro"); keydup(KF9, "bind-to-key"); keydup(KF10, "display-version"); keydup(KSF1, "up-window"); keydup(KSF2, "back-page"); keydup(KSF3, "shrink-window"); keydup(KSF4, "back-window"); keydup(KSF5, "only-window"); keydup(KSF6, "file-read"); keydup(KSF7, "file-write"); keydup(KSF8, "end-macro"); keydup(KSF9, "display-bindings"); keydup(KSF10, "quit"); /* * Bind all positions that correspond * to characters in the Amiga alternate * character set to "ins-self". These characters may * be used just like any other character. */ if ((sp=symlookup("ins-self")) == NULL) abort(); for (i=0xA0; i<0xFF; ++i) { if (binding[i] != NULL) abort(); binding[i] = sp; ++sp->s_nkey; } } -h- ttymenu.c Wed Apr 23 08:53:04 1986 ttymenu.c /* * Name: MicroEmacs * Commodore Amiga Intuition menus * Version: 31 * Last edit: 20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * Created: 20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic */ #include #include #include #include #include #undef TRUE #undef FALSE #include "def.h" /* Also includes "sysdef.h" and "ttydef.h" */ /* * When ttgetc() sees a menu selection event, it stuffs * the sequence M~ into the input buffer, and * caches the menu number and item number for later. * This sequence is translated into the internal key code * KMENU, similar to KHELP and the other function keys. * * The menu item names are chosen to be relatively close * to the extended function names, so a user can usually * figure out the key binding of a menu item by searching * through the "display-bindings" buffer for something * that's close. */ /* * Commands for managing files */ static struct MenuBinding FileItems[] = { { "Read File", "file-read", }, { "Save File", "file-save", }, { "Visit File", "file-visit", }, { "Write File", "file-write" }, { "Insert File", "file-insert" }, { "Set File Name", "set-file-name" }, { "Quit", "quit", } }; /* * Commands for various editing functions */ static struct MenuBinding EditItems[] = { { "Forward Del Char", "forw-del-char" }, { "Kill Line", "kill-line" }, { "Yank", "yank" }, { "Delete Blank Lines", "del-blank-lines" }, { "NL And Indent", "ins-nl-and-indent" }, { "Twiddle", "twiddle" }, { "Quote Character", "quote" } }; /* * Movement commands */ static struct MenuBinding MoveItems[] = { { "Beg. Of Line", "goto-bol" }, { "Beg. Of Paragraph", "goto-bop" }, { "Beg. Of Buffer", "goto-bob" }, { "End Of Line", "goto-eol" }, { "End Of Paragraph", "goto-eop" }, { "End Of Buffer", "goto-eob" }, { "Goto Line", "goto-line" }, { "Show Cursor Pos", "display-position" } }; /* * Commands for searching and replacing */ static struct MenuBinding SearchItems[] = { { "Search Again", "search-again" }, { "Forward I-Search", "forw-i-search" }, { "Backward I-Search", "back-i-search" }, { "Forward Search", "forw-search" }, { "Backward Search", "back-search" }, { "Query Replace", "query-replace" }, }; /* * Commands that manipulate words */ static struct MenuBinding WordItems[] = { { "Forward Word", "forw-word" }, { "Backward Word", "back-word" }, { "Forward Del Word", "forw-del-word" }, { "Backward Del Word", "back-del-word" }, { "Capitalize Word", "cap-word" }, { "Lowercase Word", "lower-word" }, { "Uppercase Word", "upper-word" }, { "Fill Paragraph", "fill-paragraph" }, { "Set Fill Column", "set-fill-column" } }; /* * Region management */ static struct MenuBinding RegionItems[] = { { "Set Mark", "set-mark" }, { "Swap Dot And Mark", "swap-dot-and-mark" }, { "Kill Region", "kill-region" }, { "Copy Region", "copy-region" }, { "Lowercase Region", "lower-region" }, { "Uppercase Region", "upper-region" } }; /* * Buffer management */ static struct MenuBinding BufferItems[] = { { "Use Buffer", "use-buffer" }, { "Kill Buffer", "kill-buffer" }, { "Display Buffers", "display-buffers" }, { "Rename Buffer", "rename-buffer" } }; /* * Commands for manipulating windows */ static struct MenuBinding WindowItems[] = { { "Refresh Screen", "refresh" }, { "Reposition Window", "reposition-window" }, { "Split Window", "split-window" }, { "One Window", "only-window" }, { "Next Window", "forw-window" }, { "Previous Window", "back-window" }, { "Move Window Down", "down-window" }, { "Move Window Up", "up-window" }, { "Enlarge Window", "enlarge-window" }, { "Shrink Window", "shrink-window" } }; /* * Miscellaneous commands */ static struct MenuBinding MiscItems[] = { { "About MicroEMACS", "display-version" }, { "Start Macro", "start-macro" }, { "End Macro", "end-macro" }, { "Execute Macro", "execute-macro" }, { "Extended Command", "extended-command" }, { "Bind Key", "bind-to-key" }, { "Display Bindings", "display-bindings" }, { "CLI Subprocess", "spawn-cli" } }; /* * The following table contains the titles, number of * items, and pointers to, the individual menus. * * The MenuWidth field is the number of characters * in the longest item name. */ static struct MenuInfo EMInfo[] = { { "File", NITEMS(FileItems), 13, &FileItems[0] }, { "Edit", NITEMS(EditItems), 18, &EditItems[0] }, { "Move", NITEMS(MoveItems), 18, &MoveItems[0] }, { "Search", NITEMS(SearchItems), 17, &SearchItems[0] }, { "Word", NITEMS(WordItems), 17, &WordItems[0] }, { "Region", NITEMS(RegionItems), 17, &RegionItems[0] }, { "Buffer", NITEMS(BufferItems), 15, &BufferItems[0] }, { "Window", NITEMS(WindowItems), 17, &WindowItems[0] }, { "Misc", NITEMS(MiscItems), 16, &MiscItems[0] } }; /* * Initialize the MicroEmacs menus. * * Returns a pointer to the first menu header in * the menu list back to the caller. * * Makes the assumption that the font for * the window being used is 8 pixels wide -- * a safe bet with the version 1.1 ROM Kernel. */ struct Menu *InitEmacsMenu() { struct Menu *EMMenu, *NewMenu(), *AddMenu(); struct MenuItem *AddNewMenuItem(), *AddItem(), *AddNewSubItem(); register struct Menu *cm; register struct MenuInfo *cinf, *lastinfo;/* current menu info */ register struct MenuBinding *cb; /* current ``binding'' */ lastinfo = &EMInfo[NITEMS(EMInfo)]; /* sentinel for loop */ for (cinf = EMInfo; cinf < lastinfo; cinf++) { if (cinf == EMInfo) /* create menu header */ EMMenu = cm = NewMenu(cinf->Name, strlen(cinf->Name) * 8 + 6, 10); else cm = AddMenu(cm, cinf->Name,strlen(cinf->Name) * 8 + 6, 10); MakeMenu(cinf,cm,cinf->MenuWidth * 8 + 2, 10); } return EMMenu; } /* * Put menu items in a menu. Width and * height control the respective * sizes of the menu items. */ static MakeMenu(cinf,cm,width,height) struct MenuInfo *cinf; struct Menu *cm; int width, height; { struct Menu *NewMenu(), *AddMenu(); struct MenuItem *AddNewMenuItem(), *AddItem(), *AddNewSubItem(); register struct MenuBinding *cb, *lastbinding; register struct MenuItem *ci; lastbinding = &cinf->Items[cinf->NumItems]; for (cb = cinf->Items; cb < lastbinding; cb++) { if (cb == cinf->Items) ci = AddNewMenuItem(cm, cb->Command, width, height); else ci = AddItem(ci, cb->Command); } } /* * Menu command. Get the name of the command to * perform from the menu binding table, then * run the command if it is found and has the * right type. Print an error if there is anything * wrong. */ extern ttmenu(); /* Defined in "ttyio.c" */ /* Returns last menu selection */ amigamenu(f, n, k) { register SYMBOL *sp, *symlookup(); register int s; char *xname; int MenuNum, ItemNum, SubItem; ttmenu(&MenuNum,&ItemNum,&SubItem); /* check for spurious numbers */ if ((MenuNum < 0) || (MenuNum >= NITEMS(EMInfo))) return (FALSE); if ((ItemNum < 0) || (ItemNum >= EMInfo[MenuNum].NumItems)) return (FALSE); xname = EMInfo[MenuNum].Items[ItemNum].Binding; if ((sp=symlookup(xname)) != NULL) return ((*sp->s_funcp)(f, n, KRANDOM)); eprintf("Unknown menu command"); return (ABORT); } -h- ttymouse.c Wed Apr 23 08:53:04 1986 ttymouse.c /* * Name: MicroEmacs * (Simple) Commodore Amiga mouse handling * Version: 31 * Last edit: 21-Apr-86 * Created: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic */ #include #include #undef TRUE #undef FALSE #include "def.h" extern int ttmouse(); /* Defined by "ttyio.c" */ extern int forwline(); /* Defined by "line.c" */ extern int forwchar(); /* Defined by "basic.c" */ /* * Handle the mouse click that's been passed * by ttgetc() and position dot where the * user pointed at. */ amigamouse(f, n, k) { register WINDOW *wp; register int dot; register int c; register int col; register int newrow, newcol; SHORT x, y; USHORT qualifier; /* figure out new screen position of dot */ ttmouse(&x, &y, &qualifier); newcol = x / 8; newrow = y / 8; /* find out which window was clicked in */ for (wp = wheadp; wp != NULL; wp = wp->w_wndp) if ((newrow >= wp->w_toprow) && (newrow < (wp->w_toprow + wp->w_ntrows))) break; /* make sure click was in a bona fide window */ if (wp == NULL) return (ABORT); /* move dot to top left of selected window */ curwp = wp; curbp = wp->w_bufp; curwp->w_dotp = wp->w_linep; curwp->w_doto = 0; /* go forward the correct # of lines */ forwline(FALSE, newrow - curwp->w_toprow, KRANDOM); /* go forward the correct # of characters */ /* need to count them out because of tabs */ col = dot = 0; while ((col < newcol) && (dot < llength(curwp->w_dotp))) { c = lgetc(curwp->w_dotp, dot++); if (c == '\t') col |= 0x07; else if (ISCTRL(c) != FALSE) ++col; ++col; } forwchar(FALSE, dot, KRANDOM); return (TRUE); }