home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / may94 / util / edit / jade.lha / Jade / src / keys.c < prev    next >
C/C++ Source or Header  |  1994-04-19  |  11KB  |  507 lines

  1. /* keys.c -- Key binding and evaluating
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24.  
  25. _PR VALUE usekey(void *, Event *, bool);
  26. _PR void keymap_sweep(void);
  27. _PR void keymap_prin(VALUE, VALUE);
  28. _PR void keys_init(void);
  29. _PR void keys_kill(void);
  30.  
  31. _PR Event *CurrentEvent;
  32. Event *CurrentEvent;
  33.  
  34. Keytab *KeytabChain;
  35. Keylist *KeylistChain;
  36.  
  37. static VALUE sym_keymap_path, sym_unbound_key_hook, NextKeymapPath;
  38.  
  39. /*
  40. ::doc:keymap_path::
  41. A list of keymaps (ie, keylists and/or keytables). When an event occurs
  42. each keymap in the list is searched for an event binding which matches
  43. it. These bindings are installed in a keymap by the function `bind-keys'.
  44. See also `next-keymap-path'.
  45. ::end::
  46. ::doc:unbound_key_hook::
  47. When no event binding can be found for an event this hook is evaluated in
  48. the standard manner (see the function `eval-hook' for details).
  49. ::end::
  50. */
  51.  
  52. static Key *
  53. findkey(VALUE v, EventDef *evd)
  54. {
  55.     Key *nxt, *k = NULL;
  56.     switch(VTYPE(v))
  57.     {
  58.     case V_Keytab:
  59.     k = VKEYTAB(v)->kt_Keys[evd->evd_Code & EV_HASH_MASK];
  60.     while(k)
  61.     {
  62.         if((k->ky_Event.evd_Type == evd->evd_Type)
  63.            && (k->ky_Event.evd_Mods == evd->evd_Mods)
  64.            && (k->ky_Event.evd_Code == evd->evd_Code))
  65.         break;
  66.         k = k->ky_Link.next;
  67.     }
  68.     break;
  69.     case V_Keylist:
  70.     k = (Key *)VKEYLIST(v)->kl_List.mlh_Head;
  71.     while((nxt = (Key *)k->ky_Link.node.mln_Succ))
  72.     {
  73.         if((k->ky_Event.evd_Type == evd->evd_Type)
  74.            && (k->ky_Event.evd_Mods == evd->evd_Mods)
  75.            && (k->ky_Event.evd_Code == evd->evd_Code))
  76.         break;
  77.         k = nxt;
  78.     }
  79.     if(!k->ky_Link.node.mln_Succ)
  80.         k = NULL;
  81.     break;
  82.     }
  83.     return(k);
  84. }
  85.  
  86. static VALUE
  87. evalbinding(EventDef *evd)
  88. {
  89.     VALUE kp;
  90.     if(!NILP(NextKeymapPath))
  91.     {
  92.     kp = NextKeymapPath;
  93.     NextKeymapPath = sym_nil;
  94.     }
  95.     else
  96.     {
  97.     if(!(kp = cmd_symbol_value(sym_keymap_path)))
  98.         return(NULL);
  99.     }
  100.     while(CONSP(kp))
  101.     {
  102.     VALUE thispath = VCAR(kp);
  103.     Key *k;
  104.     switch(VTYPE(thispath))
  105.     {
  106.     case V_Symbol:
  107.         if(!(thispath = cmd_symbol_value(thispath))
  108.          || (!KEYTABP(thispath) && !KEYLISTP(thispath)))
  109.         break;
  110.         /* FALL THROUGH */
  111.     case V_Keytab:
  112.     case V_Keylist:
  113.         k = findkey(thispath, evd);
  114.         if(k)
  115.         return(k->ky_Form);
  116.         break;
  117.     }
  118.     kp = VCDR(kp);
  119.     }
  120.     return(NULL);
  121. }
  122.  
  123. /*
  124.  * `OSInputMsg' is the raw input event from the window-system, this is
  125.  * only used to cook a string from.
  126.  * `ev' is the translation of `OSInputMsg'.
  127.  */
  128. VALUE
  129. usekey(void *OSInputMsg, Event *ev, bool cursState)
  130. {
  131.     VALUE cmd, result = sym_nil;
  132.     VW *vw = CurrVW;
  133.     bool inmulti = !NILP(NextKeymapPath);
  134.     CurrentEvent = ev;
  135.     resettitle(vw);
  136.     cmd = evalbinding(&ev->ev_EventDef);
  137.     if(cmd)
  138.     {
  139.     if(cursState)
  140.     {
  141.         cursor(vw, CURS_OFF);
  142.         cursState = FALSE;
  143.     }
  144.     switch(VTYPE(cmd))
  145.     {
  146.     case V_Symbol:
  147.         result = funcall(cmd, sym_nil);
  148.         break;
  149.     case V_Cons:
  150.         if(VCAR(cmd) == sym_lambda)
  151.         {
  152.         result = funcall(cmd, sym_nil);
  153.         break;
  154.         }
  155.         /* FALL THROUGH */
  156.     default:
  157.         result = cmd_eval(cmd);
  158.     }
  159.     }
  160.     else if(inmulti)
  161.     beep(vw);
  162.     else if(ev->ev_EventDef.evd_Type == EV_TYPE_KEYBD)
  163.     {
  164.     u_char buff[256];
  165.     int len;
  166.     if((len = cookkey(OSInputMsg, buff, 256 - 1)) > 0)
  167.     {
  168.         if(cursState)
  169.         {
  170.         cursor(vw, CURS_OFF);
  171.         cursState = FALSE;
  172.         }
  173.         buff[len] = 0;
  174.         if((!(result = cmd_eval_hook2(sym_unbound_key_hook, sym_nil)))
  175.            || NILP(result))
  176.         {
  177.         if(!readonly(vw->vw_Tx) && padcursor(vw))
  178.         {
  179.             POS start, tmp;
  180.             start = tmp = vw->vw_CursorPos;
  181.             insertstrn(vw->vw_Tx, buff, len, &tmp);
  182.             flaginsertion(vw->vw_Tx, &start, &vw->vw_CursorPos);
  183.             result = sym_t;
  184.         }
  185.         else
  186.             result = NULL;
  187.         }
  188.     }
  189.     else if(len < 0)
  190.         settitle("error: key translation screwup");
  191.     }
  192.     CurrentEvent = NULL;
  193.     if(CurrVW)
  194.     {
  195.     refreshworld();
  196.     if(!cursState)
  197.         cursor(CurrVW, CURS_ON);
  198.     }
  199.     return(result);
  200. }
  201.  
  202. void
  203. keymap_sweep(void)
  204. {
  205.     Keytab *kt = KeytabChain;
  206.     Keylist *kl = KeylistChain;
  207.     KeytabChain = NULL;
  208.     KeylistChain = NULL;
  209.     while(kt)
  210.     {
  211.     Keytab *nxtkt = kt->kt_Next;
  212.     if(!GC_MARKEDP(kt))
  213.     {
  214.         int i;
  215.         for(i = 0; i < 128; i++)
  216.         {
  217.         Key *this = kt->kt_Keys[i];
  218.         while(this)
  219.         {
  220.             Key *nxt = this->ky_Link.next;
  221.             mystrfree(this);
  222.             this = nxt;
  223.         }
  224.         }
  225.         myfree(kt);
  226.     }
  227.     else
  228.     {
  229.         GC_CLR(kt);
  230.         kt->kt_Next = KeytabChain;
  231.         KeytabChain = kt;
  232.     }
  233.     kt = nxtkt;
  234.     }
  235.     while(kl)
  236.     {
  237.     Keylist *nxtkl = kl->kl_Next;
  238.     if(!GC_MARKEDP(kl))
  239.     {
  240.         Key *this, *next;
  241.         this = (Key *)kl->kl_List.mlh_Head;
  242.         while((next = (Key *)this->ky_Link.node.mln_Succ))
  243.         {
  244.         mystrfree(this);
  245.         this = next;
  246.         }
  247.         mystrfree(kl);
  248.     }
  249.     else
  250.     {
  251.         GC_CLR(kl);
  252.         kl->kl_Next = KeylistChain;
  253.         KeylistChain = kl;
  254.     }
  255.     kl = nxtkl;
  256.     }
  257. }
  258. void
  259. keymap_prin(VALUE strm, VALUE obj)
  260. {
  261.     switch(VTYPE(obj))
  262.     {
  263.     case V_Keytab:
  264.     streamputs(strm, "#<key-table>", FALSE);
  265.     break;
  266.     case V_Keylist:
  267.     streamputs(strm, "#<key-list>", FALSE);
  268.     break;
  269.     }
  270. }
  271.  
  272. _PR VALUE cmd_make_keytab(void);
  273. DEFUN("make-keytab", cmd_make_keytab, subr_make_keytab, (void), V_Subr0, DOC_make_keytab) /*
  274. ::doc:make_keytab::
  275. (make-keytab)
  276. Return a new key-table suitable for storing bindings in.
  277. ::end:: */
  278. {
  279.     Keytab *kt = mycalloc(sizeof(Keytab));
  280.     if(kt)
  281.     {
  282.     kt->kt_Type = V_Keytab;
  283.     kt->kt_Next = KeytabChain;
  284.     KeytabChain = kt;
  285.     }
  286.     return(kt);
  287. }
  288.  
  289. _PR VALUE cmd_make_keylist(void);
  290. DEFUN("make-keylist", cmd_make_keylist, subr_make_keylist, (void), V_Subr0, DOC_make_keylist) /*
  291. ::doc:make_keylist::
  292. (make-keylist)
  293. Return a new key-list suitable for storing bindings in.
  294. ::end:: */
  295. {
  296.     Keylist *kl = mystralloc(sizeof(Keylist));
  297.     if(kl)
  298.     {
  299.     kl->kl_Type = V_Keylist;
  300.     kl->kl_Next = KeylistChain;
  301.     KeylistChain = kl;
  302.     NewMList(&kl->kl_List);
  303.     }
  304.     return(kl);
  305. }
  306.  
  307. _PR VALUE cmd_bind_keys(VALUE args);
  308. DEFUN("bind-keys", cmd_bind_keys, subr_bind_keys, (VALUE args), V_SubrN, DOC_bind_keys) /*
  309. ::doc:bind_keys::
  310. (bind-keys KEY-MAP { KEY-DESCRIPTION FUNCTION }...)
  311. ::end:: */
  312. {
  313.     bool rc = TRUE;
  314.     bool iskt;
  315.     VALUE km, arg1, res = NULL;
  316.     if(!CONSP(args))
  317.     return(NULL);
  318.     km = VCAR(args);
  319.     switch(VTYPE(km))
  320.     {
  321.     case V_Keytab:
  322.     iskt = TRUE;
  323.     break;
  324.     case V_Keylist:
  325.     iskt = FALSE;
  326.     break;
  327.     default:
  328.     goto end;
  329.     }
  330.     args = VCDR(args);
  331.     while(rc && CONSP(args) && CONSP(VCDR(args)))
  332.     {
  333.     EventDef ie;
  334.     Key *rt;
  335.     arg1 = VCAR(args);
  336.     args = VCDR(args);
  337.     ie.evd_Type = ie.evd_Mods = ie.evd_Code = 0;
  338.     if(STRINGP(arg1))
  339.     {
  340.         if(!lookupevent(&ie, VSTR(arg1)))
  341.         goto end;
  342.     }
  343.     else
  344.     {
  345.         cmd_signal(sym_bad_event_desc, LIST_1(arg1));
  346.         goto end;
  347.     }
  348.     rc = FALSE;
  349.     rt = mystralloc(sizeof(Key));
  350.     if(rt)
  351.     {
  352.         if(iskt)
  353.         {
  354.         u_long entry = ie.evd_Code & EV_HASH_MASK;
  355.         rt->ky_Link.next = VKEYTAB(km)->kt_Keys[entry];
  356.         VKEYTAB(km)->kt_Keys[entry] = rt;
  357.         }
  358.         else
  359.         InsertM(&VKEYLIST(km)->kl_List, &rt->ky_Link.node, NULL);
  360.         rt->ky_Form = VCAR(args);
  361.         args = VCDR(args);
  362.         rt->ky_Event = ie;
  363.         rc = TRUE;
  364.     }
  365.     else
  366.         goto end;
  367.     }
  368.     if(rc)
  369.     res = (sym_t);
  370. end:
  371.     return(res);
  372. }
  373.  
  374. _PR VALUE cmd_unbind_keys(VALUE args);
  375. DEFUN("unbind-keys", cmd_unbind_keys, subr_unbind_keys, (VALUE args), V_SubrN, DOC_unbind_keys) /*
  376. ::doc:unbind_keys::
  377. (unbind-keys KEY-MAP KEY-DESCRIPTION...)
  378. ::end:: */
  379. {
  380.     bool rc = TRUE;
  381.     bool iskt;
  382.     VALUE km, arg1, res = NULL;
  383.     if(!CONSP(args))
  384.     return(NULL);
  385.     km = VCAR(args);
  386.     args = VCDR(args);
  387.     switch(VTYPE(km))
  388.