home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / util / edit / jade / src / keys.c < prev    next >
C/C++ Source or Header  |  1994-10-04  |  16KB  |  624 lines

  1. /* keys.c -- Key binding and evaluating (this should be called events.c)
  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. #include <stdlib.h>
  25.  
  26. /* Function to make a hash key from an event (c == code, m == modifiers)  */
  27. #define KEYTAB_HASH_FUN(c,m) (((c) * 33) + (((m) & EV_MOD_MASK)))
  28.  
  29. #define KEYTAB_SIZE 127
  30.  
  31. _PR VALUE usekey(void *, u_long, u_long, bool);
  32. _PR bool print_event_prefix(void);
  33. _PR void keys_init(void);
  34.  
  35. /* current_event holds the event we're processing (or 0s), last_event
  36.    contains the previously processed event.  */
  37. _PR u_long current_event[2], last_event[2];
  38. u_long current_event[2], last_event[2];
  39.  
  40. /* Pointer to the window system's representation of the current_event,
  41.    used for cooking events into strings.  */
  42. static void *current_os_event;
  43.  
  44. /* print_prefix means echo all events upto the end of the key-sequence.
  45.    printed_this_prefix says the last event has been echoed. */
  46. static bool print_prefix, printed_this_prefix;
  47.  
  48. /* Buffer holding the events making this key-sequence. */
  49. #define EVENT_BUFSIZ 20
  50. static u_long event_buf[EVENT_BUFSIZ]; /* one event = (code,mods) */
  51. static int event_index;
  52.  
  53. static VALUE sym_keymap_path, sym_unbound_key_hook, sym_esc_means_meta,
  54.          next_keymap_path, sym_keymap;
  55.  
  56. /* TRUE when the Meta qualifier should be added to the next event. */
  57. static bool pending_meta;
  58.  
  59. /* This doesn't belong here but I couldn't find anywhere else :-( */
  60. _PR VALUE sym_idle_hook;
  61. VALUE sym_idle_hook;
  62.  
  63. /* Some doc strings
  64. ::doc:keymap_path::
  65. A list of keymaps (ie, keylists and/or keytables). When an event occurs
  66. each keymap in the list is searched for an event binding which matches
  67. it. These bindings are installed in a keymap by the function `bind-keys'.
  68. See also `next-keymap-path'.
  69. ::end::
  70. ::doc:unbound_key_hook::
  71. When no event binding can be found for an event this hook is evaluated in
  72. the standard manner (see the function `eval-hook' for details).
  73. ::end::
  74. ::doc:esc_means_meta::
  75. When this variable is non-nil the `ESC' key means that the next event
  76. is qualified by the `Meta' modifier.
  77. This feature is included mainly for compatibility with GNU Emacs.
  78. ::end::
  79. ::doc:idle_hook::
  80. This hook gets evaluated every second while the editor is idle. Don't depend
  81. on how regularly this gets called, any events from the window-system will
  82. delay it. Also, auto-saving files and garbage-collection take precedence
  83. when there's idle time available. Use this hook sparingly, or for short
  84. periods only!
  85. ::end::
  86. */
  87.  
  88. /* Search the keymap KM for a binding of CODE&MODS.  */
  89. static VALUE
  90. findkey(VALUE km, u_long code, u_long mods)
  91. {
  92.     switch(VTYPE(km))
  93.     {
  94.     case V_Vector:
  95.     if(VVECT(km)->vc_Size != KEYTAB_SIZE)
  96.         return(NULL);
  97.     km = VVECT(km)->vc_Array[KEYTAB_HASH_FUN(code, mods) % KEYTAB_SIZE];
  98.     break;
  99.     case V_Cons:
  100.     km = VCDR(km);
  101.     break;
  102.     }
  103.     while(CONSP(km))
  104.     {
  105.     VALUE this = VCAR(km);
  106.     if((VNUM(VVECTI(this, KEY_MODS)) == mods)
  107.        && (VNUM(VVECTI(this, KEY_CODE)) == code))
  108.         return(this);
  109.     km = VCDR(km);
  110.     }
  111.     return(NULL);
  112. }
  113.  
  114. /* Search for a binding of CODE&MODS.  */
  115. static VALUE
  116. lookup_binding(u_long code, u_long mods)
  117. {
  118.     VALUE kp;
  119.     if(!NILP(next_keymap_path))
  120.     {
  121.     kp = next_keymap_path;
  122.     next_keymap_path = sym_nil;
  123.     }
  124.     else
  125.     {
  126.     kp = cmd_symbol_value(sym_keymap_path, sym_t);
  127.     if(VOIDP(kp))
  128.         return(NULL);
  129.     }
  130.     while(CONSP(kp))
  131.     {
  132.     VALUE thispath = VCAR(kp);
  133.     VALUE k;
  134.     if(SYMBOLP(thispath))
  135.         thispath = cmd_symbol_value(thispath, sym_t);
  136.     if(!VOIDP(thispath))
  137.     {
  138.         if(!NILP(cmd_keymapp(thispath)))
  139.         {
  140.         k = findkey(thispath, code, mods);
  141.         if(k && VECTORP(k))
  142.             return(VVECTI(k, KEY_COMMAND));
  143.         }
  144.     }
  145.     kp = VCDR(kp);
  146.     }
  147.     return(NULL);
  148. }
  149.  
  150. /* Process the event CODE+MODS, CURS-STATE is TRUE if the cursor is drawn.
  151.    OS-INPUT-MSG is the raw input event from the window-system, this is
  152.    only used to cook a string from.  */
  153. VALUE
  154. usekey(void *OSInputMsg, u_long code, u_long mods, bool cursState)
  155. {
  156.     VALUE result = sym_nil;
  157.     event_buf[event_index++] = code;
  158.     event_buf[event_index++] = mods;
  159.     if(event_index == EVENT_BUFSIZ)
  160.     event_index = 0;
  161.     printed_this_prefix = FALSE;
  162.     if(!NILP(VSYM(sym_esc_means_meta)->sym_Value)
  163.        && !pending_meta
  164.        && (code == esc_code) && (mods == esc_mods))
  165.     {
  166.     /* Treat this ESC as a Meta-prefix. */
  167.     pending_meta = TRUE;
  168.     }
  169.     else
  170.     {
  171.     VALUE cmd;
  172.     VW *vw = curr_vw;
  173.     bool inmulti = !(NILP(next_keymap_path)
  174.              || (next_keymap_path == sym_t));
  175.     if(pending_meta)
  176.     {
  177.         mods |= EV_MOD_META;
  178.         pending_meta = FALSE;
  179.     }
  180.     current_event[0] = code;
  181.     current_event[1] = mods;
  182.     current_os_event = OSInputMsg;
  183.     reset_message(vw);
  184.     cmd = lookup_binding(code, mods);
  185.     if(cmd)
  186.     {
  187.         if(cursState)
  188.         {
  189.         cursor(vw, CURS_OFF);
  190.         cursState = FALSE;
  191.         }
  192.         result = cmd_call_command(cmd, sym_nil);
  193.     }
  194.     else if(inmulti)
  195.         beep(vw);
  196.     else
  197.     {
  198.         if(cursState)
  199.         {
  200.         cursor(vw, CURS_OFF);
  201.         cursState = FALSE;
  202.         }
  203.         result = cmd_eval_hook2(sym_unbound_key_hook, sym_nil);
  204.         if(result && !NILP(result))
  205.         undo_distinct();
  206.         else if(result && (mods & EV_TYPE_KEYBD) && OSInputMsg)
  207.         {
  208.         u_char buff[256];
  209.         int len;
  210.         if((len = cook_key(OSInputMsg, buff, 256 - 1)) >= 0)
  211.         {
  212.             buff[len] = 0;
  213.             if(len > 0)
  214.             {
  215.             if(!read_only(vw->vw_Tx))
  216.             {
  217.                 POS tmp = vw->vw_CursorPos;
  218.                 if(last_command != sym_t)
  219.                 undo_new_group();
  220.                 if(pad_cursor(vw))
  221.                 insert_string(vw->vw_Tx, buff, len, &tmp);
  222.                 last_command = sym_t;
  223.                 result = sym_t;
  224.             }
  225.             else
  226.                 result = NULL;
  227.             }
  228.         }
  229.         else
  230.             message("error: key translation screwup");
  231.         }
  232.     }
  233.     last_event[0] = current_event[0];
  234.     last_event[1] = current_event[1];
  235.     current_event[0] = current_event[1] = 0;
  236.     current_os_event = NULL;
  237.     }
  238.     if(curr_vw)
  239.     {
  240.     if(print_prefix)
  241.     {
  242.         print_event_prefix();
  243.         if(NILP(next_keymap_path)
  244.            && !pending_meta)
  245.         {
  246.         print_prefix = FALSE;
  247.         }
  248.     }
  249.     std_message(curr_vw);
  250.     refresh_world();
  251.     if(!cursState)
  252.         cursor(curr_vw, CURS_ON);
  253.     }
  254.     if(NILP(next_keymap_path) && !pending_meta)
  255.     event_index = 0;
  256.     return(result);
  257. }
  258.  
  259. _PR VALUE cmd_make_keytab(void);
  260. DEFUN("make-keytab", cmd_make_keytab, subr_make_keytab, (void), V_Subr0, DOC_make_keytab) /*
  261. ::doc:make_keytab::
  262. make-keytab
  263.  
  264. Return a new key-table suitable for storing bindings in. This is a 127
  265. element vector, each element is an empty list of bindings.
  266. ::end:: */
  267. {
  268.     return(cmd_make_vector(make_number(KEYTAB_SIZE), sym_nil));
  269. }
  270.  
  271. _PR VALUE cmd_make_keylist(void);
  272. DEFUN("make-keylist", cmd_make_keylist, subr_make_keylist, (void), V_Subr0, DOC_make_keylist) /*
  273. ::doc:make_keylist::
  274. make-keylist
  275.  
  276. Return a new key-list suitable for storing bindings in. This is a cons
  277. cell looking like `(keymap . LIST-OF-BINDINGS)', LIST-OF-BINDINGS starts
  278. off empty.
  279. ::end:: */
  280. {
  281.     return(cmd_cons(sym_keymap, sym_nil));
  282. }
  283.  
  284. _PR VALUE cmd_bind_keys(VALUE args);
  285. DEFUN("bind-keys", cmd_bind_keys, subr_bind_keys, (VALUE args), V_SubrN, DOC_bind_keys) /*
  286. ::doc:bind_keys::
  287. bind-keys KEY-MAP { EVENT-DESCRIPTION COMMAND }...
  288. ::end:: */
  289. {
  290.     bool rc = TRUE;
  291.     VALUE km, arg1, res = NULL;
  292.     if(!CONSP(args))
  293.     return(NULL);
  294.     km = VCAR(args);
  295.     args = VCDR(args);
  296.     while(rc && CONSP(args) && CONSP(VCDR(args)))
  297.     {
  298.     u_long code, mods;
  299.     VALUE key;
  300.     arg1 = VCAR(args);
  301.     args = VCDR(args);
  302.     if(STRINGP(arg1))
  303.     {
  304.         if(!lookup_event(&code, &mods, VSTR(arg1)))
  305.         goto end;
  306.     }
  307.     el