static char rcsid[] = "$Id: bind.c,v 1.6 1992/12/28 00:38:14 mike Exp $"; /* $Log: bind.c,v $ * Revision 1.6 1992/12/28 00:38:14 mike * - Unused `pkeys' have a value of 0 instead of `SHIFT'. This avoids * some complications. * - `bind-to-key' complains in case of a bogus key description. * * Revision 1.5 1992/11/08 23:29:54 mike * - Added view mode. * * Revision 1.4 1992/10/28 15:07:08 mike * - Removed two `toggle_cursor()' calls from `getkey()'. They are handled * by `Eget_key()' now. * * Revision 1.3 1992/10/02 22:31:40 mike * - Some changes for the Atari ST/TT version. * * Revision 1.2 1992/09/14 18:03:42 mike * - First set of changes for the Atari ST/TT version. * * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * BIND.C: handle all the bindings and stuff */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include #include "me2.h" #include "mm.h" #include "bind.h" extern int apropos(), dscrib_bindings(), arg_count(), quit(), ctrlg(), /* Abort out of things */ ctlxlp(), ctlxrp(), ctlxe(), /* Begin, End, Run macro */ load_Mutt_file(), fileread(), filevisit(), filewrite(), filesave(), insert_file(), goto_BoL(), goto_EoL(), goto_BoB(), goto_EoB(), backchar(), forwline(), backline(), forwpage(), forwchar(), backpage(), backword(), forwword(), forwdel(), backdel(), swapmark(), setmark(), nextwind(), prevwind(), onlywind(), splitwind(), mvdnwind(), mvupwind(), switch_to_buffer(), reposition(), refresh(), tab(), newline(), indent(), openline(), quote(), cut_line(), yank(), delfword(), delbword(), cutregion(), copyregion(), delregion(), spawn_shell(), shell_command(), metacmds(), version(), describe_key(); int bind_to_key(), localbind(); /* * Command table. This table is in ASCII order. * NOTE: * If you change this table, make SURE you: * - Sort it (use filter) * - Reorder the defaultkeys table below. You can use bind.mut to do * this (see below). */ Binding bindings[] = { "ME-command", metacmds, 0, "abort", ctrlg, 0, "apropos", apropos, 0, "beginning-of-buffer", goto_BoB, 0, "beginning-of-line", goto_BoL, 0, "bind-local-key", localbind, 0, "bind-to-key", bind_to_key, 0, "copy-region", copyregion, 0, "cut-line", cut_line, 1, "cut-previous-word", delbword, 1, "cut-region", cutregion, 1, "cut-word", delfword, 1, "delete-character", forwdel, 1, "delete-other-windows", onlywind, 0, "delete-previous-character", backdel, 1, "delete-region", delregion, 1, "describe-bindings", dscrib_bindings, 0, "end-macro", ctlxrp, 0, "end-of-buffer", goto_EoB, 0, "end-of-line", goto_EoL, 0, "exchange-dot-and-mark", swapmark, 0, "execute-macro", ctlxe, 0, "exit", quit, 0, "insert-file", insert_file, 1, "load", load_Mutt_file, 0, "newline", newline, 1, "newline-and-indent", indent, 1, "next-character", forwchar, 0, "next-line", forwline, 0, "next-page", forwpage, 0, "next-window", nextwind, 0, "next-word", forwword, 0, "open-line", openline, 1, "previous-character", backchar, 0, "previous-line", backline, 0, "previous-page", backpage, 0, "previous-window", prevwind, 0, "previous-word", backword, 0, "quote", quote, 1, "read-file", fileread, 1, "refresh-screen", refresh, 0, "reposition-window", reposition, 0, "save-buffer", filesave, 1, "scroll-down", mvdnwind, 0, "scroll-up", mvupwind, 0, "set-the-mark", setmark, 0, "shell-command", shell_command, 0, "spawn-shell", spawn_shell, 0, "split-window", splitwind, 0, "start-macro", ctlxlp, 0, "switch-to-buffer", switch_to_buffer, 0, "tab", tab, 1, "universal-argument", arg_count, 0, "version", version, 0, "visit-file", filevisit, 0, "write-file", filewrite, 0, "yank", yank, 1, "zkey", describe_key, 0 }; int sbsize = NITEMS(bindings); #if 0 * Table format: * ,SYS,/* [stuff] */ * Format must be maintained so that I can maintain this table with a Mutt * program (stepping-stone in bind.mut). #endif static UKey defaultkeys[] = { CTRL|'G', SYS,1, /* abort */ CTRL|'H', SYS,14, /* delete-previous-character */ CTRL|'I', SYS,51, /* tab */ CTRL|'F', SYS,27, /* next-character */ CTRL|'Y', SYS,56, /* yank */ CTRL|'U', SYS,52, /* universal-argument */ CTRL|'B', SYS,33, /* previous-character */ META|'B', SYS,37, /* previous-word */ META|'<', SYS,3, /* beginning-of-buffer */ CTRL|'A', SYS,4, /* beginning-of-line */ META|'W', SYS,7, /* copy-region */ CTRL|'D', SYS,12, /* delete-character */ CTRL|'?', SYS,12, /* delete-character DEL(7F) == ^? == ^D */ CTRL|'K', SYS,8, /* cut-line */ META|'D', SYS,11, /* cut-word */ META|CTRL|'?', SYS,11, /* cut-word aka M-DEL */ META|CTRL|'H', SYS,9, /* cut-previous-word */ CTLX|'1', SYS,13, /* delete-other-windows */ META|'>', SYS,18, /* end-of-buffer */ CTLX|')', SYS,17, /* end-macro */ CTRL|'E', SYS,19, /* end-of-line */ CTLX|CTRL|'X', SYS,20, /* exchange-dot-and-mark */ META|'X', SYS,0, /* ME-command */ CTLX|'E', SYS,21, /* execute-macro */ CTLX|'!', SYS,46, /* shell-command */ CTRL|'C', SYS,22, /* exit */ CTLX|CTRL|'C', SYS,22, /* exit Hard quit */ META|'F', SYS,31, /* next-word */ CTLX|'I', SYS,23, /* insert-file */ CTRL|'W', SYS,10, /* cut-region */ CTRL|'M', SYS,25, /* newline */ CTRL|'J', SYS,26, /* newline-and-indent */ META|CTRL|'O', SYS,26, /* newline-and-indent */ CTRL|'N', SYS,28, /* next-line */ CTRL|'V', SYS,29, /* next-page */ CTLX|'O', SYS,30, /* next-window */ CTRL|'O', SYS,32, /* open-line */ CTRL|'P', SYS,34, /* previous-line */ META|'V', SYS,35, /* previous-page */ CTLX|'P', SYS,36, /* previous-window */ CTRL|'^', SYS,38, /* quote */ CTRL|'Q', SYS,38, /* quote Often unreachable */ CTLX|CTRL|'R', SYS,39, /* read-file */ CTRL|'L', SYS,40, /* refresh-screen */ META|'!', SYS,41, /* reposition-window */ CTLX|CTRL|'S', SYS,42, /* save-buffer */ CTLX|CTRL|'N', SYS,43, /* scroll-down */ CTLX|CTRL|'P', SYS,44, /* scroll-up */ CTRL|'@', SYS,45, /* set-the-mark */ META|' ', SYS,45, /* set-the-mark */ CTRL|'Z', SYS,47, /* spawn-shell */ CTLX|'2', SYS,48, /* split-window */ CTLX|'(', SYS,49, /* start-macro */ CTLX|'B', SYS,50, /* switch-to-buffer */ CTLX|CTRL|'F', SYS,54, /* visit-file */ CTLX|CTRL|'V', SYS,54, /* visit-file */ CTLX|CTRL|'W', SYS,55, /* write-file */ META|'?', SYS,2, /* apropos */ /* softkeys */ SOFKEY|'A', SYS,3, /* beginning-of-buffer : home */ SOFKEY|'B', SYS,18, /* end-of-buffer : end */ SOFKEY|'C', SYS,34, /* previous-line : up arrow */ SOFKEY|'D', SYS,28, /* next-line : down arrow */ SOFKEY|'E', SYS,27, /* next-character : right arrow */ SOFKEY|'F', SYS,33, /* previous-character : left arrow */ SOFKEY|'H', SYS,12, /* delete-character : delete */ SOFKEY|'I', SYS,35, /* previous-page : page down */ SOFKEY|'J', SYS,29, /* next-page : page up */ #ifdef atarist SOFKEY|'K', SYS,2, /* apropos : help */ #else SOFKEY|'K', SYS,8, /* cut-line : clear line */ SOFKEY|'N', SYS,45, /* set-the-mark : select */ #endif SOFKEY|'O', SYS,43, /* scroll-down : roll up */ SOFKEY|'P', SYS,44, /* scroll-up : roll down */ #ifdef atarist SOFKEY|'Q', SYS,4, /* beginning-of-lie : shift left */ SOFKEY|'R', SYS,19, /* end-of-line : shift right */ SOFKEY|'S', SYS,37, /* previous-word : Ctrl left */ SOFKEY|'T', SYS,31, /* next-word : Ctrl right */ SOFKEY|'U', SYS,57, /* describe-key : Ctrl help */ #endif }; /* Use binary search to find system function name * returns TRUE if found, i = index of word * FALSE if not found, i = element after were word should go */ lookupfcn(name,i) char *name; int *i; /* lookup system name */ { register int lower = 0, upper = sbsize -1, x, j; while (lower<=upper) { j = (lower+upper)/2; if ((x = strcmp(name,bindings[j].name))>0) lower = j +1; else if (x<0) upper = j -1; else { *i = j; return TRUE; } } return FALSE; } extern int arg_flag, arg_prefix, pgm_flag, pgm_prefix; /* in mmaux.c */ int gimmehelp = 1; metacmds(f,n) int f,n; { char name[64]; int i,s; if ((s = mlreply("Run command: ", name, sizeof(name), CC_SYS|CC_PGM)) != TRUE) return s; if ((i = MMpgm_lookup(name)) != -1) /* first see if Mutt program */ { pgm_flag = f; pgm_prefix = n; arg_flag = FALSE; arg_prefix = 1; return MMrun_pgm(i); } if (lookupfcn(name,&i)) /* maybe its a built-in */ { if ((curbp->b_flags & BFVIEW) && bindings[i].prohibited) { view_mode_violation(); return ABORT; } return (*bindings[i].fcn)(f,n); } /* its no nothing */ mlwrite("Command \"%s\" does not exist",name); if (gimmehelp == 1) dscrib_bindings(FALSE,1); return ABORT; } /* ******************************************************************** */ /* ********** Keys **************************************************** */ /* ******************************************************************** */ KeyCode pkeys[PKEYS] = { CTRL | '[', /* ESCape */ CTRL | 'X', /* Control X */ 0, /* undefined */ 0, /* undefined */ }; /* Read in a key. * Do the standard keyboard preprocessing. * Convert the keys to the internal character set. */ #if ATARI KeyCode getkey() { KeyCode key; key = Eget_key(pkeys,0); return key; } KeyCode getkeyX(key) int key; /* A value from evnt_keybd */ { return Eget_key(pkeys,key); } #else KeyCode getkey() { return Eget_key(pkeys); } #endif /* convert a key string to keycode */ KeyCode to_keycode(ptr,prefixable) char *ptr; { return Eto_keycode(pkeys,ptr,prefixable); } void xpandkey(buf,keycode) char *buf; KeyCode keycode; { Expand_key(pkeys,keycode,buf); } /* ******************************************************************** */ /* ************** Key Tables ****************************************** */ /* ******************************************************************** */ static int binder(), bind_key(); KeyTable gkeys = initial_dTable_data(gkeys); /* global key table */ UKey *lookupkey(keycode) KeyCode keycode; /* lookup user key */ { UKey *key; if ((key = (UKey *)Efind_key(&curbp->lkeys,keycode)) || (key = (UKey *)Efind_key(&gkeys,keycode))) return key; return NULL; } /* Run whatever is bound to a key. Whatever is a built-in command or * Mutt program. * Input: * keycode : The key to run * f : The C-u flag. * n : The C-u count. * status : exit status of the command just run (TRUE, FALSE, ABORT). * Returns: * TRUE : keycode is bound to something. * FALSE : keycode is not bound. */ int run_key(keycode,f,n,status) KeyCode keycode; int f,n,*status; { UKey *key; if ((key = lookupkey(keycode))) { switch (key->type) { case SYS: if ((curbp->b_flags & BFVIEW) && bindings[key->index].prohibited) { view_mode_violation(); return TRUE; /* It is bound, yes, although not exec'ed */ } *status = (*bindings[key->index].fcn)(f,n); return TRUE; case PGM: pgm_flag = f; pgm_prefix = n; arg_flag = FALSE; arg_prefix = 1; *status = MMrun_pgm((int)key->index); return TRUE; } } return FALSE; /* ain't nothing I know about */ } bind_to_key(f,n) { return binder(&gkeys); } localbind(f,n) { return binder(&curbp->lkeys); } static int binder(kt) KeyTable *kt; { char kbuf[25], name[80]; int s; KeyCode kc; if (mlreply("Bind command: ",name,sizeof(name),CC_SYS|CC_PGM) == ABORT) return ABORT; if (0 == strcmp("clear-keymap",name)) { clear_keytable(kt); return TRUE; } if ((s = mlreply("To key: ",kbuf,sizeof(kbuf),0)) == ABORT) return s; if (s == FALSE) { kbuf[0] = 0xD; kbuf[1] = '\0'; } /* CR */ if (!(kc = Eto_keycode(pkeys,kbuf,TRUE))) { mlwrite("Bogus key description : %s",kbuf); return FALSE; } if ((s = bind_key(kt,kc,name)) == FALSE) mlwrite("%s not found",name); return s; } static int bind_key(kt,keycode,name) KeyTable *kt; KeyCode keycode; char *name; { int index, type; UKey *key; if (*name == '\0') { Eunbind_key(kt,keycode); return TRUE; } if ((index = MMpgm_lookup(name)) != -1) type = PGM; else if (lookupfcn(name,&index)) type = SYS; else return FALSE; if (!(key = (UKey *)(Ekalloc(kt,keycode)))) { mlwrite("No memory for key table!"); return ABORT; } key->keycode = keycode; key->type = type; key->index = index; return TRUE; } /* Initalize the global key map. Call this while initializing ME2. * Returns: * TRUE: all OK. * FALSE: No memory. */ initkeys() { /* if fails: system probably to low on mem to do anything */ if (!xpand_dTable(&gkeys,NITEMS(defaultkeys),0,25)) return FALSE; blkmov((char *)gkeys.table,(char *)defaultkeys,sizeof(defaultkeys)); return TRUE; } /* Initialize the buffer local keymap. This needs to be called when a * buffer is created. */ void init_buffer_keys(bp) Buffer *bp; { initialize_dTable(&bp->lkeys,sizeof(UKey)); } /******************** pgms and keys *********************************/ static int dead_pgm_key(key) UKey *key; { return key->type == PGM && pgmdead((int)key->index); } /* Get rid of keys bound to dead pgms. * Assume this don't happen very often. */ void packkeys() { Buffer *bp; Epack_keytable(&gkeys,dead_pgm_key); for (bp = first_buffer; bp; bp = bp->nextb) Epack_keytable(&bp->lkeys,dead_pgm_key); }