home *** CD-ROM | disk | FTP | other *** search
- /* Manipulation of keymaps
- Copyright (C) 1985, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
- Copyright (C) 1995 Board of Trustees, University of Illinois
- Totally redesigned by jwz in 1991.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Mule 2.0. Not synched with FSF. Substantially
- different from FSF. */
-
-
- #include <config.h>
- #include "lisp.h"
-
- #include "buffer.h"
- #include "bytecode.h"
- #include "commands.h"
- #include "elhash.h"
- #include "events.h"
- #include "device.h"
- #include "frame.h"
- #include "insdel.h"
- #include "keymap.h"
- #include "window.h"
-
-
- /* A keymap contains four slots:
-
- parents Ordered list of keymaps to search after
- this one if no match is found.
- Keymaps can thus be arranged in a hierarchy.
-
- table A hash table, hashing keysyms to their bindings.
- As in the rest of emacs, a keysym is either a symbol or
- an integer, which is an ASCII code (of one of the printing
- ASCII characters: not 003 meaning C-c, for instance).
- It can also be an integer representing a modifier
- combination; this will be greater than or equal to
- (1 << 16).
-
- inverse_table A hash table, hashing bindings to the list of keysyms
- in this keymap which are bound to them. This is to make
- the Fwhere_is_internal() function be fast. It needs to be
- fast because we want to be able to call it in realtime to
- update the keyboard-equivalents on the pulldown menus.
- Values of the table are either atoms (keysyms)
- or a dotted list of keysyms.
-
- sub_maps_cache An alist; for each entry in this keymap whose binding is
- a keymap (that is, Fkeymapp()) this alist associates that
- keysym with that binding. This is used to optimize both
- Fwhere_is_internal() and Faccessible_keymaps(). This slot
- gets set to the symbol `t' every time a change is made to
- this keymap, causing it to be recomputed when next needed.
-
- prompt See `set-keymap-prompt'.
-
- default_binding See `set-keymap-default-binding'.
-
- Sequences of keys are stored in the obvious way: if the sequence of keys
- "abc" was bound to some command `foo', the hierarchy would look like
-
- keymap-1: associates "a" with keymap-2
- keymap-2: associates "b" with keymap-3
- keymap-3: associates "c" with foo
-
- However, bucky bits ("modifiers" to the X-minded) are represented in the
- keymap hierarchy as well. (This lets us use EQable objects as hash keys.)
- Each combination of modifiers (e.g. control-hyper) gets its own submap
- off of the main map. The hash key for a modifier combination is
- a large integer, computed by MAKE_MODIFIER_HASH_KEY().
-
- If the key `C-a' was bound to some command, the hierarchy would look like
-
- keymap-1: associates the integer (MOD_CONTROL << 16) with keymap-2
- keymap-2: associates "a" with the command
-
- Similarly, if the key `C-H-a' was bound to some command, the hierarchy
- would look like
-
- keymap-1: associates the integer ((MOD_CONTROL | MOD_HYPER) << 16)
- with keymap-2
- keymap-2: associates "a" with the command
-
- Note that a special exception is made for the meta modifier, in order
- to deal with ESC/meta lossage. Any key combination containing the
- meta modifier is first indexed off of the main map into the meta
- submap (with hash key (MOD_META << 16)) and then indexed off of the
- meta submap with the meta modifier removed from the key combination.
- For example, when associating a command with C-M-H-a, we'd have
-
- keymap-1: associates the integer (MOD_META << 16) with keymap-2
- keymap-2: associates the integer ((MOD_CONTROL | MOD_HYPER) << 16)
- with keymap-3
- keymap-3: associates "a" with the command
-
- Note that keymap-2 might have normal bindings in it; these would be
- for key combinations containing only the meta modifier, such as
- M-y or meta-backspace.
-
- If the command that "a" was bound to in keymap-3 was itself a keymap,
- then that would make the key "C-M-H-a" be a prefix character.
-
- Note that this new model of keymaps takes much of the magic away from
- the Escape key: the value of the variable `esc-map' is no longer indexed
- in the `global-map' under the ESC key. It's indexed under the integer
- (MOD_META << 16). This is not user-visible, however; none of the "bucky"
- maps are.
-
- There is a hack in Flookup_key() that makes (lookup-key global-map "\^[")
- and (define-key some-random-map "\^[" my-esc-map) work as before, for
- compatibility.
-
- Since keymaps are opaque, the only way to extract information from them
- is with the functions lookup-key, key-binding, local-key-binding, and
- global-key-binding, which work just as before, and the new function
- map-keymap, which is roughly analagous to maphash.
-
- Note that map-keymap perpetuates the illusion that the "bucky" submaps
- don't exist: if you map over a keymap with bucky submaps, it will also
- map over those submaps. It does not, however, map over other random
- submaps of the keymap, just the bucky ones.
-
- One implication of this is that when you map over `global-map', you will
- also map over `esc-map'. It is merely for compatibility that the esc-map
- is accessible at all; I think that's a bad thing, since it blurs the
- distinction between ESC and "meta" even more. "M-x" is no more a two-
- key sequence than "C-x" is.
-
- */
-
- struct keymap
- {
- struct lcrecord_header header;
- Lisp_Object parents; /* Keymaps to be searched after this one
- * An ordered list */
- Lisp_Object prompt; /* Qnil or a string to print in the minibuffer
- * when reading from this keymap */
-
- Lisp_Object table; /* The contents of this keymap */
- Lisp_Object inverse_table; /* The inverse mapping of the above */
-
- Lisp_Object default_binding; /* Use this if no other binding is found
- * (this overrides parent maps and the
- * normal global-map lookup). */
-
-
- Lisp_Object sub_maps_cache; /* Cache of directly inferior keymaps;
- This holds an alist, of the key and the
- maps, or the modifier bit and the map.
- If this is the symbol t, then the cache
- needs to be recomputed.
- */
- int fullness; /* How many entries there are in this table.
- This should be the same as the fullness
- of the `table', but hash.c is broken. */
- Lisp_Object name; /* Just for debugging convenience */
- };
-
- DECLARE_LRECORD (keymap, struct keymap);
- #define XKEYMAP(x) XRECORD (x, keymap, struct keymap)
- #define XSETKEYMAP(x, p) XSETRECORD (x, p, keymap)
- #define KEYMAPP(x) RECORDP (x, keymap)
- #define CHECK_KEYMAP(x, i) CHECK_RECORD (x, keymap)
-
- /* Hash key is shifted so it can't conflict with eight-bit
- string-char constituents */
- #define MAKE_MODIFIER_HASH_KEY(modifier) (make_number ((modifier) << 16))
- #define MODIFIER_HASH_KEY_P(x) ((INTP((x))) ? (XINT ((x)) >> 16) : 0)
-
-
-
- /* Actually allocate storage for these variables */
-
- static Lisp_Object Vcurrent_global_map; /* Always a keymap */
-
- static Lisp_Object Vmouse_grabbed_buffer;
-
- /* Alist of minor mode variables and keymaps. */
- static Lisp_Object Qminor_mode_map_alist;
-
- static Lisp_Object Voverriding_local_map;
-
-
- /* This is incremented whenever a change is made to a keymap. This is
- so that things which care (such as the menubar code) can recompute
- privately-cached data when the user has changed keybindings.
- */
- int keymap_tick;
-
- /* Prefixing a key with this character is the same as sending a meta bit. */
- Lisp_Object Vmeta_prefix_char;
-
- Lisp_Object Qkeymap;
- Lisp_Object Qkeymapp;
-
- Lisp_Object Vsingle_space_string;
-
- Lisp_Object Qsuppress_keymap;
-
- Lisp_Object Qmodeline_map;
- Lisp_Object Qtoolbar_map;
-
- static void describe_command (Lisp_Object definition);
- static void describe_map (Lisp_Object keymap, Lisp_Object elt_prefix,
- void (*elt_describer) (Lisp_Object),
- int partial,
- Lisp_Object shadow,
- int mice_only_p);
- Lisp_Object Qcontrol, Qctrl, Qmeta, Qsuper, Qhyper, Qalt, Qshift;
- /* Lisp_Object Qsymbol; defined in general.c */
- Lisp_Object Qbutton0, Qbutton1, Qbutton2, Qbutton3, Qbutton4, Qbutton5,
- Qbutton6, Qbutton7;
- Lisp_Object Qbutton0up, Qbutton1up, Qbutton2up, Qbutton3up, Qbutton4up,
- Qbutton5up, Qbutton6up, Qbutton7up;
- Lisp_Object Qmenu_selection;
-
- /* Kludge kludge kludge */
- Lisp_Object QLFD, QTAB, QRET, QESC, QDEL, QSPC, QBS;
-
-
- /************************************************************************/
- /* The keymap Lisp object */
- /************************************************************************/
-
- static Lisp_Object mark_keymap (Lisp_Object, void (*) (Lisp_Object));
- static void print_keymap (Lisp_Object, Lisp_Object, int);
- /* No need for keymap_equal #### Why not? */
- DEFINE_LRECORD_IMPLEMENTATION ("keymap", keymap,
- mark_keymap, print_keymap, 0, 0, 0,
- struct keymap);
- static Lisp_Object
- mark_keymap (Lisp_Object obj, void (*markobj) (Lisp_Object))
- {
- struct keymap *keymap = XKEYMAP (obj);
- ((markobj) (keymap->parents));
- ((markobj) (keymap->prompt));
- ((markobj) (keymap->inverse_table));
- ((markobj) (keymap->sub_maps_cache));
- ((markobj) (keymap->default_binding));
- ((markobj) (keymap->name));
- return (keymap->table);
- }
-
- static void
- print_keymap (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- struct keymap *keymap = XKEYMAP (obj);
- char buf[200];
- int size = XINT (Fkeymap_fullness (obj));
- if (print_readably)
- error ("printing unreadable object #<keymap 0x%x>", keymap->header.uid);
- write_c_string ("#<keymap ", printcharfun);
- if (!NILP (keymap->name))
- print_internal (keymap->name, printcharfun, 1);
- sprintf (buf, "%s%d entr%s 0x%x>",
- ((NILP (keymap->name)) ? "" : " "),
- size,
- ((size == 1) ? "y" : "ies"),
- keymap->header.uid);
- write_c_string (buf, printcharfun);
- }
-
-
- /************************************************************************/
- /* Traversing keymaps and their parents */
- /************************************************************************/
-
- static Lisp_Object
- traverse_keymaps (Lisp_Object start_keymap, Lisp_Object start_parents,
- Lisp_Object (*mapper) (Lisp_Object keymap, void *mapper_arg),
- void *mapper_arg)
- {
- /* This function can GC */
- Lisp_Object keymap;
- Lisp_Object tail = start_parents;
- Lisp_Object malloc_sucks[10];
- Lisp_Object malloc_bites = Qnil;
- int stack_depth = 0;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
- GCPRO4 (*malloc_sucks, malloc_bites, start_keymap, tail);
- gcpro1.nvars = 0;
-
- start_keymap = get_keymap (start_keymap, 1, 1);
- keymap = start_keymap;
- /* Hack special-case parents at top-level */
- tail = ((!NILP (tail)) ? tail : XKEYMAP (keymap)->parents);
-
- for (;;)
- {
- Lisp_Object result;
-
- QUIT;
- result = ((mapper) (keymap, mapper_arg));
- if (!NILP (result))
- {
- while (CONSP (malloc_bites))
- {
- struct Lisp_Cons *victim = XCONS (malloc_bites);
- malloc_bites = victim->cdr;
- free_cons (victim);
- }
- UNGCPRO;
- return (result);
- }
- if (NILP (tail))
- {
- if (stack_depth == 0)
- {
- UNGCPRO;
- return (Qnil); /* Nothing found */
- }
- stack_depth--;
- if (CONSP (malloc_bites))
- {
- struct Lisp_Cons *victim = XCONS (malloc_bites);
- tail = victim->car;
- malloc_bites = victim->cdr;
- free_cons (victim);
- }
- else
- {
- tail = malloc_sucks[stack_depth];
- gcpro1.nvars = stack_depth;
- }
- keymap = XCAR (tail);
- tail = XCDR (tail);
- }
- else
- {
- Lisp_Object parents;
-
- keymap = XCAR (tail);
- tail = XCDR (tail);
- parents = XKEYMAP (keymap)->parents;
- if (!CONSP (parents))
- ;
- else if (NILP (tail))
- /* Tail-recurse */
- tail = parents;
- else
- {
- if (CONSP (malloc_bites))
- malloc_bites = Fcons (tail, malloc_bites);
- else if (stack_depth < countof (malloc_sucks))
- {
- malloc_sucks[stack_depth++] = tail;
- gcpro1.nvars = stack_depth;
- }
- else
- {
- /* *&@##[*&^$ C. @#[$*&@# Unix. Losers all. */
- int i;
- for (i = 0, malloc_bites = Qnil;
- i < countof (malloc_sucks);
- i++)
- malloc_bites = Fcons (malloc_sucks[i], malloc_bites);
- gcpro1.nvars = 0;
- }
- tail = parents;
- }
- }
- keymap = get_keymap (keymap, 1, 1);
- if (EQ (keymap, start_keymap))
- {
- signal_simple_error ("Cyclic keymap indirection",
- start_keymap);
- }
- }
- }
-
-
- /************************************************************************/
- /* Some low-level functions */
- /************************************************************************/
-
- static unsigned int
- bucky_sym_to_bucky_bit (Lisp_Object sym)
- {
- if (EQ (sym, Qcontrol))
- return MOD_CONTROL;
- else if (EQ (sym, Qmeta))
- return MOD_META;
- else if (EQ (sym, Qsuper))
- return MOD_SUPER;
- else if (EQ (sym, Qhyper))
- return MOD_HYPER;
- else if (EQ (sym, Qalt) || EQ (sym, Qsymbol)) /* #### - reverse compat */
- return MOD_ALT;
- else if (EQ (sym, Qshift))
- return MOD_SHIFT;
- else
- return 0;
- }
-
- static Lisp_Object
- control_meta_superify (Lisp_Object frob, unsigned int modifiers)
- {
- if (modifiers == 0)
- return frob;
- frob = Fcons (frob, Qnil);
- if (modifiers & MOD_SHIFT)
- frob = Fcons (Qshift, frob);
- if (modifiers & MOD_ALT)
- frob = Fcons (Qalt, frob);
- if (modifiers & MOD_HYPER)
- frob = Fcons (Qhyper, frob);
- if (modifiers & MOD_SUPER)
- frob = Fcons (Qsuper, frob);
- if (modifiers & MOD_CONTROL)
- frob = Fcons (Qcontrol, frob);
- if (modifiers & MOD_META)
- frob = Fcons (Qmeta, frob);
- return (frob);
- }
-
- static Lisp_Object
- make_key_description (CONST struct key_data *key, int prettify)
- {
- Lisp_Object keysym = key->keysym;
- unsigned int modifiers = key->modifiers;
-
- if (prettify && INTP (keysym))
- {
- /* This is a little slow, but (control a) is prettier than (control 65).
- It's now ok to do this for digit-chars too, since we've fixed the
- bug where \9 read as the integer 9 instead of as the symbol with
- "9" as its name.
- */
- /* !!#### I'm not sure how correct this is. */
- Bufbyte str [1 + MAX_EMCHAR_LEN];
- Bytecount count = emchar_to_charptr (XINT (keysym), str);
- str[count] = 0;
- keysym = intern ((char *) str);
- }
- return (control_meta_superify (keysym, modifiers));
- }
-
-
- /************************************************************************/
- /* Low-level keymap-store functions */
- /************************************************************************/
-
- static Lisp_Object
- raw_lookup_key (Lisp_Object keymap,
- CONST struct key_data *raw_keys, int raw_keys_count,
- int keys_so_far, int accept_default);
-
- /* Relies on caller to gc-protect args */
- static Lisp_Object
- keymap_lookup_directly (Lisp_Object keymap,
- Lisp_Object keysym, unsigned int modifiers)
- {
- struct keymap *k;
-
- if ((modifiers & ~(MOD_CONTROL | MOD_META | MOD_SUPER | MOD_HYPER
- | MOD_ALT | MOD_SHIFT)) != 0)
- abort ();
-
- k = XKEYMAP (keymap);
-
- /* If the keysym is a one-character symbol, use the char code instead. */
- if (SYMBOLP (keysym) && string_length (XSYMBOL (keysym)->name) == 1)
- keysym = make_number (string_char (XSYMBOL (keysym)->name, 0));
-
- if (modifiers & MOD_META) /* Utterly hateful ESC lossage */
- {
- Lisp_Object submap = Fgethash (MAKE_MODIFIER_HASH_KEY (MOD_META),
- k->table, Qnil);
- if (NILP (submap))
- return (Qnil);
- k = XKEYMAP (submap);
- modifiers &= ~MOD_META;
- }
-
- if (modifiers != 0)
- {
- Lisp_Object submap = Fgethash (MAKE_MODIFIER_HASH_KEY (modifiers),
- k->table, Qnil);
- if (NILP (submap))
- return (Qnil);
- k = XKEYMAP (submap);
- }
- return (Fgethash (keysym, k->table, Qnil));
- }
-
- static void
- keymap_store_inverse_internal (Lisp_Object inverse_table,
- Lisp_Object keysym,
- Lisp_Object value)
- {
- Lisp_Object keys = Fgethash (value, inverse_table, Qunbound);
-
- if (EQ (keys, Qunbound))
- {
- keys = keysym;
- /* Don't cons this unless necessary */
- /* keys = Fcons (keysym, Qnil); */
- Fputhash (value, keys, inverse_table);
- }
-
- else if (!CONSP (keys))
- {
- /* Now it's necessary to cons */
- keys = Fcons (keys, keysym);
- Fputhash (value, keys, inverse_table);
- }
- else
- {
- while (CONSP (Fcdr (keys)))
- keys = XCDR (keys);
- XCDR (keys) = Fcons (XCDR (keys), keysym);
- /* No need to call puthash because we've destructively
- modified the list tail in place */
- }
- }
-
-
- static void
- keymap_delete_inverse_internal (Lisp_Object inverse_table,
- Lisp_Object keysym,
- Lisp_Object value)
- {
- Lisp_Object keys = Fgethash (value, inverse_table, Qunbound);
- Lisp_Object new_keys = keys;
- Lisp_Object tail;
- Lisp_Object *prev;
-
- if (EQ (keys, Qunbound))
- abort ();
-
- for (prev = &new_keys, tail = new_keys;
- ;
- prev = &(XCDR (tail)), tail = XCDR (tail))
- {
- if (EQ (tail, keysym))
- {
- *prev = Qnil;
- break;
- }
- else if (EQ (keysym, XCAR (tail)))
- {
- *prev = XCDR (tail);
- break;
- }
- }
-
- if (NILP (new_keys))
- Fremhash (value, inverse_table);
- else if (!EQ (keys, new_keys))
- /* Removed the first elt */
- Fputhash (value, new_keys, inverse_table);
- /* else the list's tail has been modified, so we don't need to
- touch the hash table again (the pointer in there is ok).
- */
- }
-
-
- static void
- keymap_store_internal (Lisp_Object keysym, struct keymap *keymap,
- Lisp_Object value)
- {
- Lisp_Object prev_value = Fgethash (keysym, keymap->table, Qnil);
-
- if (EQ (prev_value, value))
- return;
- if (!NILP (prev_value))
- keymap_delete_inverse_internal (keymap->inverse_table,
- keysym, prev_value);
- if (NILP (value))
- {
- keymap->fullness--;
- if (keymap->fullness < 0) abort ();
- Fremhash (keysym, keymap->table);
- }
- else
- {
- if (NILP (prev_value))
- keymap->fullness++;
- Fputhash (keysym, value, keymap->table);
- keymap_store_inverse_internal (keymap->inverse_table,
- keysym, value);
- }
- keymap_tick++;
- }
-
-
- static Lisp_Object
- create_bucky_submap (struct keymap *k, unsigned int modifiers,
- Lisp_Object parent_for_debugging_info)
- {
- Lisp_Object submap = Fmake_sparse_keymap ();
- /* User won't see this, but it is nice for debugging Emacs */
- XKEYMAP (submap)->name
- = control_meta_superify (parent_for_debugging_info, modifiers);
- /* Invalidate cache */
- k->sub_maps_cache = Qt;
- keymap_store_internal (MAKE_MODIFIER_HASH_KEY (modifiers), k, submap);
- return (submap);
- }
-
-
- /* Relies on caller to gc-protect keymap, keysym, value */
- static void
- keymap_store (Lisp_Object keymap, CONST struct key_data *key,
- Lisp_Object value)
- {
- Lisp_Object keysym = key->keysym;
- unsigned int modifiers = key->modifiers;
- struct keymap *k;
-
- if ((modifiers & ~(MOD_CONTROL | MOD_META | MOD_SUPER | MOD_HYPER
- | MOD_ALT | MOD_SHIFT)) != 0)
- abort ();
-
- k = XKEYMAP (keymap);
-
- /* If the keysym is a one-character symbol, use the char code instead. */
- if (SYMBOLP (keysym) && string_length (XSYMBOL (keysym)->name) == 1)
- keysym = make_number (string_char (XSYMBOL (keysym)->name, 0));
-
- if (modifiers & MOD_META) /* Utterly hateful ESC lossage */
- {
- Lisp_Object submap = Fgethash (MAKE_MODIFIER_HASH_KEY (MOD_META),
- k->table, Qnil);
- if (NILP (submap))
- submap = create_bucky_submap (k, MOD_META, keymap);
- k = XKEYMAP (submap);
- modifiers &= ~MOD_META;
- }
-
- if (modifiers != 0)
- {
- Lisp_Object submap = Fgethash (MAKE_MODIFIER_HASH_KEY (modifiers),
- k->table, Qnil);
- if (NILP (submap))
- submap = create_bucky_submap (k, modifiers, keymap);
- k = XKEYMAP (submap);
- }
- k->sub_maps_cache = Qt; /* Invalidate cache */
- keymap_store_internal (keysym, k, value);
- }
-
-
- /************************************************************************/
- /* Listing the submaps of a keymap */
- /************************************************************************/
-
- struct keymap_submaps_closure
- {
- Lisp_Object *result_locative;
- };
-
- static void
- keymap_submaps_mapper_0 (CONST void *hash_key, void *hash_contents,
- void *keymap_submaps_closure)
- {
- /* This function can GC */
- Lisp_Object contents;
- VOID_TO_LISP (contents, hash_contents);
- /* Perform any autoloads, etc */
- (void) Fkeymapp (contents);
- }
-
- static void
- keymap_submaps_mapper (CONST void *hash_key, void *hash_contents,
- void *keymap_submaps_closure)
- {
- /* This function can GC */
- Lisp_Object key, contents;
- Lisp_Object *result_locative;
- struct keymap_submaps_closure *cl = keymap_submaps_closure;
- CVOID_TO_LISP (key, hash_key);
- VOID_TO_LISP (contents, hash_contents);
- result_locative = cl->result_locative;
-
- if (!NILP (Fkeymapp (contents)))
- *result_locative = Fcons (Fcons (key, contents), *result_locative);
- }
-
- static int map_keymap_sort_predicate (Lisp_Object obj1, Lisp_Object obj2,
- Lisp_Object pred);
-
- static Lisp_Object
- keymap_submaps (Lisp_Object keymap)
- {
- /* This function can GC */
- struct keymap *k = XKEYMAP (keymap);
-
- if (EQ (k->sub_maps_cache, Qt)) /* Unknown */
- {
- Lisp_Object result = Qnil;
- struct gcpro gcpro1, gcpro2;
- struct keymap_submaps_closure keymap_submaps_closure;
-
- GCPRO2 (keymap, result);
- keymap_submaps_closure.result_locative = &result;
- /* Do this first pass to touch (and load) any autoloaded maps */
- elisp_maphash (keymap_submaps_mapper_0, k->table,
- &keymap_submaps_closure);
- result = Qnil;
- elisp_maphash (keymap_submaps_mapper, k->table,
- &keymap_submaps_closure);
- /* keep it sorted so that the result of accessible-keymaps is ordered */
- k->sub_maps_cache = list_sort (result,
- Qnil,
- map_keymap_sort_predicate);
- UNGCPRO;
- }
- return (k->sub_maps_cache);
- }
-
-
- /************************************************************************/
- /* Basic operations on keymaps */
- /************************************************************************/
-
- static Lisp_Object
- make_keymap (int size)
- {
- Lisp_Object result = Qnil;
- struct keymap *keymap = alloc_lcrecord (sizeof (struct keymap),
- lrecord_keymap);
-
- XSETKEYMAP (result, keymap);
-
- keymap->parents = Qnil;
- keymap->table = Qnil;
- keymap->prompt = Qnil;
- keymap->default_binding = Qnil;
- keymap->inverse_table = Qnil;
- keymap->sub_maps_cache = Qnil; /* No possible submaps */
- keymap->fullness = 0;
- if (size != 0) /* hack for copy-keymap */
- {
- keymap->table = Fmake_hashtable (make_number (size));
- /* Inverse table is often less dense because of duplicate key-bindings.
- If not, it will grow anyway. */
- keymap->inverse_table = Fmake_hashtable (make_number (size * 3 / 4));
- }
- keymap->name = Qnil;
- return (result);
- }
-
- DEFUN ("make-keymap", Fmake_keymap, Smake_keymap, 0, 0, 0,
- "Construct and return a new keymap object.\n\
- All entries in it are nil, meaning \"command undefined\".")
- ()
- {
- return make_keymap (60);
- }
-
- DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 0, 0,
- "Construct and return a new keymap object.\n\
- All entries in it are nil, meaning \"command undefined\". The only\n\
- difference between this function and make-keymap is that this function\n\
- returns a \"smaller\" keymap (one that is expected to contain fewer\n\
- entries). As keymaps dynamically resize, the distinction is not great.")
- ()
- {
- return make_keymap (8);
- }
-
- DEFUN ("keymap-parents", Fkeymap_parents, Skeymap_parents, 1, 1, 0,
- "Return the `parent' keymaps of the given keymap, or nil.\n\
- The parents of a keymap are searched for keybindings when a key sequence\n\
- isn't bound in this one. `(current-global-map)' is the default parent\n\
- of all keymaps.")
- (keymap)
- Lisp_Object keymap;
- {
- keymap = get_keymap (keymap, 1, 1);
- return (Fcopy_sequence (XKEYMAP (keymap)->parents));
- }
-
-
-
- static Lisp_Object
- traverse_keymaps_noop (Lisp_Object keymap, void *arg)
- {
- return (Qnil);
- }
-
- DEFUN ("set-keymap-parents", Fset_keymap_parents, Sset_keymap_parents, 2, 2, 0,
- "Sets the `parent' keymaps of the given keymap.\n\
- The parents of a keymap are searched for keybindings when a key sequence\n\
- isn't bound in this one. `(current-global-map)' is the default parent\n\
- of all keymaps.")
- (keymap, parents)
- Lisp_Object keymap, parents;
- {
- /* This function can GC */
- Lisp_Object k;
- struct gcpro gcpro1, gcpro2;
-
- GCPRO2 (keymap, parents);
- keymap = get_keymap (keymap, 1, 1);
-
- if (KEYMAPP (parents)) /* backwards-compatibility */
- parents = list1 (parents);
- if (!NILP (parents))
- {
- Lisp_Object tail = parents;
- while (!NILP (tail))
- {
- QUIT;
- CHECK_CONS (tail, 0);
- k = XCAR (tail);
- /* Require that it be an actual keymap object, rather than a symbol
- with a (crockish) symbol-function which is a keymap */
- CHECK_KEYMAP (k, 1); /* get_keymap (k, 1, 1); */
- tail = XCDR (tail);
- }
- }
-
- /* Check for circularities */
- traverse_keymaps (keymap, parents, traverse_keymaps_noop, 0);
- keymap_tick++;
- XKEYMAP (keymap)->parents = Fcopy_sequence (parents);
- UNGCPRO;
- return (parents);
- }
-
- DEFUN ("set-keymap-name", Fset_keymap_name, Sset_keymap_name, 2, 2, 0,
- "Sets the `name' of the KEYMAP to NEW-NAME\n\
- The name is only a debugging convenience; it is not used except\n\
- when printing the keymap.")
- (keymap, new_name)
- Lisp_Object keymap, new_name;
- {
- keymap = get_keymap (keymap, 1, 1);
-
- XKEYMAP (keymap)->name = new_name;
- return (new_name);
- }
-
- /*
- * DEFUN ("keymap-name", Fkeymap_name, Skeymap_name, 1, 1, 0,
- * "Return the `name' of KEYMAP.\n\
- * The name is only a debugging convenience; it is not used except\n\
- * when printing the keymap.")
- * (keymap)
- * Lisp_Object keymap;
- * {
- * keymap = get_keymap (keymap, 1, 1);
- *
- * return (XKEYMAP (keymap)->name);
- * }
- */
-
- DEFUN ("set-keymap-prompt", Fset_keymap_prompt, Sset_keymap_prompt, 2, 2, 0,
- "Sets the `prompt' of KEYMAP to string NEW-PROMPT, or `nil'\n\
- if no prompt is desired. The prompt is shown in the echo-area\n\
- when reading a key-sequence to be looked-up in this keymap.")
- (keymap, new_prompt)
- Lisp_Object keymap, new_prompt;
- {
- keymap = get_keymap (keymap, 1, 1);
-
- if (!NILP (new_prompt))
- CHECK_STRING (new_prompt, 1);
-
- XKEYMAP (keymap)->prompt = new_prompt;
- return (new_prompt);
- }
-
- static Lisp_Object
- keymap_prompt_mapper (Lisp_Object keymap, void *arg)
- {
- return (XKEYMAP (keymap)->prompt);
- }
-
-
- DEFUN ("keymap-prompt", Fkeymap_prompt, Skeymap_prompt, 1, 2, 0,
- "Return the `prompt' of the given keymap.\n\
- If non-nil, the prompt is shown in the echo-area\n\
- when reading a key-sequence to be looked-up in this keymap.")
- (keymap, use_inherited)
- Lisp_Object keymap, use_inherited;
- {
- /* This function can GC */
- Lisp_Object prompt;
-
- keymap = get_keymap (keymap, 1, 1);
- prompt = XKEYMAP (keymap)->prompt;
- if (!NILP (prompt) || NILP (use_inherited))
- return (prompt);
- else
- return (traverse_keymaps (keymap, Qnil,
- keymap_prompt_mapper, 0));
- }
-
- DEFUN ("set-keymap-default-binding",
- Fset_keymap_default_binding, Sset_keymap_default_binding, 2, 2, 0,
- "Sets the default binding of KEYMAP to COMMAND, or `nil'\n\
- if no default is desired. The default-binding is returned when\n\
- no other binding for a key-sequence is found in the keymap.\n\
- If a keymap has a non-nil default-binding, neither the keymap's\n\
- parents nor the current global map are searched for key bindings.")
- (keymap, command)
- Lisp_Object keymap, command;
- {
- /* This function can GC */
- keymap = get_keymap (keymap, 1, 1);
-
- XKEYMAP (keymap)->default_binding = command;
- return (command);
- }
-
- DEFUN ("keymap-default-binding",
- Fkeymap_default_binding, Skeymap_default_binding, 1, 1, 0,
- "Return the default binding of KEYMAP, or `nil' if it has none.\n\
- The default-binding is returned when no other binding for a key-sequence\n\
- is found in the keymap.\n\
- If a keymap has a non-nil default-binding, neither the keymap's\n\
- parents nor the current global map are searched for key bindings.")
- (keymap)
- Lisp_Object keymap;
- {
- /* This function can GC */
- keymap = get_keymap (keymap, 1, 1);
- return (XKEYMAP (keymap)->default_binding);
- }
-
- DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
- "Return t if ARG is a keymap object.\n\
- The keymap may be autoloaded first if necessary.")
- (object)
- Lisp_Object object;
- {
- /* This function can GC */
- Lisp_Object tem = get_keymap (object, 0, 1);
- return ((KEYMAPP (tem)) ? Qt : Qnil);
- }
-
- /* Check that OBJECT is a keymap (after dereferencing through any
- symbols). If it is, return it.
-
- If AUTOLOAD is non-zero and OBJECT is a symbol whose function value
- is an autoload form, do the autoload and try again.
-
- ERRORP controls how we respond if OBJECT isn't a keymap.
- If ERRORP is non-zero, signal an error; otherwise, just return Qnil.
- */
- Lisp_Object
- get_keymap (Lisp_Object object, int errorp, int autoload)
- {
- /* This function can GC */
- while (1)
- {
- Lisp_Object tem = indirect_function (object, 0);
-
- if (KEYMAPP (tem))
- return tem;
- /* Should we do an autoload? */
- else if (autoload
- /* (autoload "filename" doc nil keymap) */
- && SYMBOLP (object)
- && CONSP (tem)
- && EQ (XCAR (tem), Qautoload)
- && EQ (Fcar (Fcdr (Fcdr (Fcdr (Fcdr (tem))))), Qkeymap))
- {
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (tem, object);
- do_autoload (tem, object);
- UNGCPRO;
- }
- else if (errorp)
- object = wrong_type_argument (Qkeymapp, object);
- else
- return Qnil;
- }
- }
-
- /* Given OBJECT which was found in a slot in a keymap,
- trace indirect definitions to get the actual definition of that slot.
- An indirect definition is a list of the form
- (KEYMAP . INDEX), where KEYMAP is a keymap or a symbol defined as one
- and INDEX is an ASCII code, or a cons of (KEYSYM . MODIFIERS).
- */
- static Lisp_Object
- get_keyelt (Lisp_Object object, int accept_default)
- {
- /* This function can GC */
- Lisp_Object map;
-
- tail_recurse:
- if (!CONSP (object))
- return (object);
-
- {
- struct gcpro gcpro1;
- GCPRO1 (object);
- map = XCAR (object);
- map = get_keymap (map, 0, 1);
- UNGCPRO;
- }
- /* If the contents are (KEYMAP . ELEMENT), go indirect. */
- if (!NILP (map))
- {
- Lisp_Object idx = Fcdr (object);
- struct key_data indirection;
- if (INTP (idx))
- {
- struct Lisp_Event event;
- event.event_type = empty_event;
- character_to_event (XINT (idx), &event, 0);
- indirection = event.event.key;
- }
- else if (CONSP (idx))
- {
- if (!INTP (XCDR (idx)))
- return (Qnil);
- indirection.keysym = XCAR (idx);
- indirection.modifiers = XINT (XCDR (idx));
- }
- else if (SYMBOLP (idx))
- {
- indirection.keysym = idx;
- indirection.modifiers = 0;
- }
- else
- {
- /* Random junk */
- return (Qnil);
- }
- return (raw_lookup_key (map, &indirection, 1, 0,
- accept_default));
- }
- else if (STRINGP (XCAR (object)))
- {
- /* If the keymap contents looks like (STRING . DEFN),
- use DEFN.
- Keymap alist elements like (CHAR MENUSTRING . DEFN)
- will be used by HierarKey menus. */
- object = XCDR (object);
- goto tail_recurse;
- }
- else
- {
- /* Anything else is really the value. */
- return (object);
- }
- }
-
- static Lisp_Object
- keymap_lookup_1 (Lisp_Object keymap, CONST struct key_data *key,
- int accept_default)
- {
- /* This function can GC */
- return (get_keyelt (keymap_lookup_directly (keymap,
- key->keysym, key->modifiers),
- accept_default));
- }
-
-
- /************************************************************************/
- /* Copying keymaps */
- /************************************************************************/
-
- struct copy_keymap_inverse_closure
- {
- Lisp_Object inverse_table;
- };
-
- static void
- copy_keymap_inverse_mapper (CONST void *hash_key, void *hash_contents,
- void *copy_keymap_inverse_closure)
- {
- Lisp_Object key, inverse_table, inverse_contents;
- struct copy_keymap_inverse_closure *closure = copy_keymap_inverse_closure;
-
- VOID_TO_LISP (inverse_table, closure);
- VOID_TO_LISP (inverse_contents, hash_contents);
- CVOID_TO_LISP (key, hash_key);
- /* copy-sequence deals with dotted lists. */
- if (CONSP (inverse_contents))
- inverse_contents = Fcopy_sequence (inverse_contents);
- Fputhash (key, inverse_contents, closure->inverse_table);
- }
-
-
- static Lisp_Object
- copy_keymap_internal (struct keymap *keymap)
- {
- Lisp_Object nkm = make_keymap (0);
- struct keymap *new_keymap = XKEYMAP (nkm);
- struct copy_keymap_inverse_closure copy_keymap_inverse_closure;
- copy_keymap_inverse_closure.inverse_table = keymap->inverse_table;
-
- new_keymap->parents = Fcopy_sequence (keymap->parents);
- new_keymap->fullness = keymap->fullness;
- new_keymap->sub_maps_cache = Qnil; /* No submaps */
- new_keymap->table = Fcopy_hashtable (keymap->table);
- new_keymap->inverse_table = Fcopy_hashtable (keymap->inverse_table);
- /* After copying the inverse map, we need to copy the conses which
- are its values, lest they be shared by the copy, and mangled.
- */
- elisp_maphash (copy_keymap_inverse_mapper, keymap->inverse_table,
- ©_keymap_inverse_closure);
- return nkm;
- }
-
-
- static Lisp_Object copy_keymap (Lisp_Object keymap);
-
- struct copy_keymap_closure
- {
- struct keymap *self;
- };
-
- static void
- copy_keymap_mapper (CONST void *hash_key, void *hash_contents,
- void *copy_keymap_closure)
- {
- /* This function can GC */
- Lisp_Object key, contents;
- struct copy_keymap_closure *closure = copy_keymap_closure;
-
- CVOID_TO_LISP (key, hash_key);
- VOID_TO_LISP (contents, hash_contents);
- /* When we encounter a keymap which is indirected through a
- symbol, we need to copy the sub-map. In v18, the form
- (lookup-key (copy-keymap global-map) "\C-x")
- returned a new keymap, not the symbol 'Control-X-prefix.
- */
- contents = get_keymap (contents,
- 0, 1); /* #### autoload GC-safe here? */
- if (KEYMAPP (contents))
- keymap_store_internal (key, closure->self,
- copy_keymap (contents));
- }
-
- static Lisp_Object
- copy_keymap (Lisp_Object keymap)
- {
- /* This function can GC */
- struct copy_keymap_closure copy_keymap_closure;
-
- keymap = copy_keymap_internal (XKEYMAP (keymap));
- copy_keymap_closure.self = XKEYMAP (keymap);
- elisp_maphash (copy_keymap_mapper,
- XKEYMAP (keymap)->table,
- ©_keymap_closure);
- return keymap;
- }
-
- DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0,
- "Return a copy of the keymap KEYMAP.\n\
- The copy starts out with the same definitions of KEYMAP,\n\
- but changing either the copy or KEYMAP does not affect the other.\n\
- Any key definitions that are subkeymaps are recursively copied.")
- (keymap)
- Lisp_Object keymap;
- {
- /* This function can GC */
- keymap = get_keymap (keymap, 1, 1);
- return copy_keymap (keymap);
- }
-
-
- static int
- keymap_fullness (Lisp_Object keymap)
- {
- /* This function can GC */
- int fullness;
- Lisp_Object sub_maps;
- struct gcpro gcpro1, gcpro2;
-
- keymap = get_keymap (keymap, 1, 1);
- fullness = XKEYMAP (keymap)->fullness;
- sub_maps = keymap_submaps (keymap);
- GCPRO2 (keymap, sub_maps);
- for (; !NILP (sub_maps); sub_maps = XCDR (sub_maps))
- {
- if (MODIFIER_HASH_KEY_P (XCAR (XCAR (sub_maps))) != 0)
- {
- Lisp_Object sub_map = XCDR (XCAR (sub_maps));
- fullness--; /* don't count bucky maps */
- fullness += keymap_fullness (sub_map);
- }
- }
- UNGCPRO;
- return (fullness);
- }
-
- DEFUN ("keymap-fullness", Fkeymap_fullness, Skeymap_fullness, 1, 1, 0,
- "Return the number of bindings in the keymap.")
- (keymap)
- Lisp_Object keymap;
- {
- /* This function can GC */
- return (make_number (keymap_fullness
- (get_keymap (keymap, 1, 1))));
- }
-
-
- /************************************************************************/
- /* Defining keys in keymaps */
- /************************************************************************/
-
- static void
- define_key_check_keysym (Lisp_Object spec,
- Lisp_Object keysym, unsigned int modifiers)
- {
- /* Now, check and massage the trailing keysym specifier. */
- if (SYMBOLP (keysym))
- {
- if (string_length (XSYMBOL (keysym)->name) == 1)
- {
- keysym = make_number (string_char (XSYMBOL (keysym)->name, 0));
- goto fixnum_keysym;
- }
- }
- else if (INTP (keysym))
- {
- fixnum_keysym:
- /* #### needs to be fixed for Mule */
- if (XINT (keysym) < ' ' || XINT (keysym) > 255)
- signal_simple_error ("keysym must be in the range 32 - 255",
- keysym);
- /* #### This bites! I want to be able to write (control shift a) */
- if (modifiers & MOD_SHIFT)
- signal_simple_error ("the `shift' modifier may not be applied to ASCII keysyms",
- spec);
- }
- else
- {
- signal_simple_error ("unknown keysym specifier",
- keysym);
- }
- }
-
-
- /* Given any kind of key-specifier, return a keysym and modifier mask.
- */
- static void
- define_key_parser (Lisp_Object spec, struct key_data *returned_value)
- {
- if (INTP (spec))
- {
- struct Lisp_Event event;
- event.event_type = empty_event;
- character_to_event (XINT (spec), &event, 0);
- returned_value->keysym = event.event.key.keysym;
- returned_value->modifiers = event.event.key.modifiers;
- }
- else if (EVENTP (spec))
- {
- switch (XEVENT (spec)->event_type)
- {
- case key_press_event:
- {
- returned_value->keysym = XEVENT (spec)->event.key.keysym;
- returned_value->modifiers = XEVENT (spec)->event.key.modifiers;
- break;
- }
- case button_press_event:
- case button_release_event:
- {
- int down = (XEVENT (spec)->event_type == button_press_event);
- switch (XEVENT (spec)->event.button.button)
- {
- case 1:
- returned_value->keysym = (down ? Qbutton1 : Qbutton1up); break;
- case 2:
- returned_value->keysym = (down ? Qbutton2 : Qbutton2up); break;
- case 3:
- returned_value->keysym = (down ? Qbutton3 : Qbutton3up); break;
- case 4:
- returned_value->keysym = (down ? Qbutton4 : Qbutton4up); break;
- case 5:
- returned_value->keysym = (down ? Qbutton5 : Qbutton5up); break;
- case 6:
- returned_value->keysym = (down ? Qbutton6 : Qbutton6up); break;
- case 7:
- returned_value->keysym = (down ? Qbutton7 : Qbutton7up); break;
- default:
- returned_value->keysym =(down ? Qbutton0 : Qbutton0up); break;
- }
- returned_value->modifiers = XEVENT (spec)->event.button.modifiers;
- break;
- }
- default:
- signal_error (Qwrong_type_argument,
- list2 (build_translated_string
- ("unable to bind this type of event"),
- spec));
- }
- }
- else if (SYMBOLP (spec))
- {
- /* Be nice, allow = to mean (=) */
- if (bucky_sym_to_bucky_bit (spec) != 0)
- signal_simple_error ("Key is a modifier name", spec);
- define_key_check_keysym (spec, spec, 0);
- returned_value->keysym = spec;
- returned_value->modifiers = 0;
- }
- else if (CONSP (spec))
- {
- unsigned int modifiers = 0;
- Lisp_Object keysym = Qnil;
- Lisp_Object rest = spec;
-
- /* First, parse out the leading modifier symbols. */
- while (CONSP (rest))
- {
- unsigned int modifier;
-
- keysym = XCAR (rest);
- modifier = bucky_sym_to_bucky_bit (keysym);
- modifiers |= modifier;
- if (!NILP (XCDR (rest)))
- {
- if (! modifier)
- signal_simple_error ("unknown modifier", keysym);
- }
- else
- {
- if (modifier)
- signal_simple_error ("nothing but modifiers here",
- spec);
- }
- rest = XCDR (rest);
- QUIT;
- }
- if (!NILP (rest))
- signal_simple_error ("dotted list", spec);
-
- define_key_check_keysym (spec, keysym, modifiers);
- returned_value->keysym = keysym;
- returned_value->modifiers = modifiers;
- }
- else
- {
- signal_simple_error ("unknown key-sequence specifier",
- spec);
- }
-
- /* Convert single-character symbols into ints, since that's the
- way the events arrive from the keyboard... */
- if (SYMBOLP (returned_value->keysym) &&
- string_length (XSYMBOL (returned_value->keysym)->name) == 1)
- {
- returned_value->keysym =
- make_number (string_char (XSYMBOL (returned_value->keysym)->name, 0));
-
- /* Detect bogus (user-provided) keysyms like '\?C-a;
- We can't do that for '\?M-a because that interferes with
- legitimate 8-bit input. */
- if (XINT (returned_value->keysym) < ' ' ||
- XINT (returned_value->keysym) > 255)
- signal_simple_error ("keysym must be in the range 32 - 255",
- returned_value->keysym);
- }
-
- if (SYMBOLP (returned_value->keysym))
- {
- char *name = (char *) string_data (XSYMBOL (returned_value->keysym)->name);
-
- /* FSFmacs uses symbols with the printed representation of keysyms in
- their names, like 'M-x, and we use the syntax '(meta x). So, to avoid
- confusion, notice the M-x syntax and signal an error - because
- otherwise it would be interpreted as a regular keysym, and would even
- show up in the list-buffers output, causing confusion to the naive.
-
- We can get away with this because none of the X keysym names contain
- a hyphen (some contain underscore, however).
-
- It might be useful to reject keysyms which are not x-valid-keysym-
- name-p, but that would interfere with various tricks we do to
- sanitize the Sun keyboards, and would make it trickier to
- conditionalize a .emacs file for multiple X servers.
- */
- if (strchr (name, '-')
- #if 1
- ||
- /* Ok, this is a bit more dubious - prevent people from doing things
- like (global-set-key 'RET 'something) because that will have the
- same problem as above. (Gag!) Maybe we should just silently
- accept these as aliases for the "real" names?
- */
- (string_length (XSYMBOL (returned_value->keysym)->name) < 4 &&
- (!strcmp (name, "LFD") ||
- !strcmp (name, "TAB") ||
- !strcmp (name, "RET") ||
- !strcmp (name, "ESC") ||
- !strcmp (name, "DEL") ||
- !strcmp (name, "SPC") ||
- !strcmp (name, "BS")))
- #endif /* unused */
- )
- signal_simple_error ("invalid keysym (see doc of define-key)",
- returned_value->keysym);
-
- /* #### Ok, this is a bit more dubious - make people not lose if they
- do things like (global-set-key 'RET 'something) because that would
- otherwise have the same problem as above. (Gag!) We silently
- accept these as aliases for the "real" names.
- */
- else if (EQ (returned_value->keysym, QLFD))
- returned_value->keysym = QKlinefeed;
- else if (EQ (returned_value->keysym, QTAB))
- returned_value->keysym = QKtab;
- else if (EQ (returned_value->keysym, QRET))
- returned_value->keysym = QKreturn;
- else if (EQ (returned_value->keysym, QESC))
- returned_value->keysym = QKescape;
- else if (EQ (returned_value->keysym, QDEL))
- returned_value->keysym = QKdelete;
- else if (EQ (returned_value->keysym, QBS))
- returned_value->keysym = QKbackspace;
- }
- }
-
- /* This piece of crap is used by macros.c */
- void
- key_desc_list_to_event (Lisp_Object list, Lisp_Object event,
- int allow_menu_events)
- {
- struct key_data raw_key;
-
- /* #### Temporary multi-device kludge. */
- if (NILP (EVENT_DEVICE (XEVENT (event))))
- EVENT_DEVICE (XEVENT (event)) = Fselected_device ();
-
- if (allow_menu_events &&
- CONSP (list) &&
- /* #### where the hell does this come from? */
- EQ (XCAR (list), Qmenu_selection))
- {
- Lisp_Object fn, arg;
- if (! NILP (Fcdr (Fcdr (list))))
- signal_simple_error ("invalid menu event desc", list);
- arg = Fcar (Fcdr (list));
- if (SYMBOLP (arg))
- fn = Qcall_interactively;
- else
- fn = Qeval;
- XEVENT (event)->channel = Qnil;
- XEVENT (event)->event_type = misc_user_event;
- XEVENT (event)->event.eval.function = fn;
- XEVENT (event)->event.eval.object = arg;
- return;
- }
-
- define_key_parser (list, &raw_key);
-
- if (EQ (raw_key.keysym, Qbutton0) || EQ (raw_key.keysym, Qbutton0up) ||
- EQ (raw_key.keysym, Qbutton1) || EQ (raw_key.keysym, Qbutton1up) ||
- EQ (raw_key.keysym, Qbutton2) || EQ (raw_key.keysym, Qbutton2up) ||
- EQ (raw_key.keysym, Qbutton3) || EQ (raw_key.keysym, Qbutton3up) ||
- EQ (raw_key.keysym, Qbutton4) || EQ (raw_key.keysym, Qbutton4up) ||
- EQ (raw_key.keysym, Qbutton5) || EQ (raw_key.keysym, Qbutton5up) ||
- EQ (raw_key.keysym, Qbutton6) || EQ (raw_key.keysym, Qbutton6up) ||
- EQ (raw_key.keysym, Qbutton7) || EQ (raw_key.keysym, Qbutton7up))
- error ("Mouse-clicks can't appear in saved keyboard macros.");
-
- XEVENT (event)->channel = Qnil;
- XEVENT (event)->event_type = key_press_event;
- XEVENT (event)->event.key.keysym = raw_key.keysym;
- XEVENT (event)->event.key.modifiers = raw_key.modifiers;
- }
-
-
- int
- event_matches_key_specifier_p (struct Lisp_Event *event,
- Lisp_Object key_specifier)
- {
- Lisp_Object event2;
- int retval;
- struct gcpro gcpro1;
-
- if (event->event_type != key_press_event || NILP (key_specifier) ||
- (INTP (key_specifier) && XINT (key_specifier) < 0))
- return 0;
-
- /* if the specifier is an integer such as 27, then it should match
- both of the events 'escape' and 'control ['. Calling
- Fcharacter_to_event() will only match 'escape'. */
- if (INTP (key_specifier))
- return XINT (key_specifier) == event_to_character (event, 0, 0, 0);
-
- /* Otherwise, we cannot call event_to_character() because we may
- be dealing with non-ASCII keystrokes. In any case, if I ask
- for 'control [' then I should get exactly that, and not
- 'escape'.
-
- However, we have to behave differently on TTY's, where 'control ['
- is silently converted into 'escape' by the keyboard driver.
- In this case, ASCII is the only thing we know about, so we have
- to compare the ASCII values. */
-
- GCPRO1 (event2);
- event2 = Fallocate_event ();
- Fcharacter_to_event (key_specifier, event2, Qnil);
- if (XEVENT (event2)->event_type != key_press_event)
- retval = 0;
- else if (DEVICE_IS_TTY (XDEVICE (EVENT_DEVICE (event))))
- {
- int ch1, ch2;
-
- ch1 = event_to_character (event, 0, 0, 0);
- ch2 = event_to_character (XEVENT (event2), 0, 0, 0);
- retval = (ch1 >= 0 && ch2 >= 0 && ch1 == ch2);
- }
- else if (EQ (event->event.key.keysym, XEVENT (event2)->event.key.keysym) &&
- event->event.key.modifiers == XEVENT (event2)->event.key.modifiers)
- retval = 1;
- else
- retval = 0;
- Fdeallocate_event (event2);
- UNGCPRO;
- return retval;
- }
-
- static int
- meta_prefix_char_p (CONST struct key_data *key)
- {
- struct Lisp_Event event;
-
- event.event_type = key_press_event;
- event.event.key.keysym = key->keysym;
- event.event.key.modifiers = key->modifiers;
- return event_matches_key_specifier_p (&event, Vmeta_prefix_char);
- }
-
- DEFUN ("event-matches-key-specifier-p",
- Fevent_matches_key_specifier_p,
- Sevent_matches_key_specifier_p,
- 2, 2, 0,
- "Return non-nil if EVENT matches KEY-SPECIFIER.\n\
- This can be useful, e.g., to determine if the user pressed `help-char' or\n\
- `quit-char'.")
- (event, key_specifier)
- Lisp_Object event, key_specifier;
- {
- CHECK_LIVE_EVENT (event, 0);
- return (event_matches_key_specifier_p (XEVENT (event), key_specifier)
- ? Qt : Qnil);
- }
-
- /* ASCII grunge.
- Given a keysym, return another keysym/modifier pair which could be
- considered the same key in an ASCII world. Backspace returns ^H, for
- example.
- */
- static void
- define_key_alternate_name (struct key_data *key,
- struct key_data *returned_value)
- {
- Lisp_Object keysym = key->keysym;
- unsigned int modifiers = key->modifiers;
- unsigned int modifiers_sans_control = (modifiers & (~MOD_CONTROL));
- unsigned int modifiers_sans_meta = (modifiers & (~MOD_META));
- returned_value->keysym = Qnil; /* By default, no "alternate" key */
- returned_value->modifiers = 0;
- #define MACROLET(k,m) do { returned_value->keysym = (k); \
- returned_value->modifiers = (m); \
- return; } while (0)
- if (modifiers_sans_meta == MOD_CONTROL)
- {
- if EQ (keysym, QKspace)
- MACROLET (make_number ('@'), modifiers);
- else if (!INTP (keysym))
- return;
- else switch (XINT (keysym))
- {
- case '@': /* c-@ => c-space */
- MACROLET (QKspace, modifiers);
- case 'h': /* c-h => backspace */
- MACROLET (QKbackspace, modifiers_sans_control);
- case 'i': /* c-i => tab */
- MACROLET (QKtab, modifiers_sans_control);
- case 'j': /* c-j => linefeed */
- MACROLET (QKlinefeed, modifiers_sans_control);
- case 'm': /* c-m => return */
- MACROLET (QKreturn, modifiers_sans_control);
- case '[': /* c-[ => escape */
- MACROLET (QKescape, modifiers_sans_control);
- default:
- return;
- }
- }
- else if (modifiers_sans_meta != 0)
- return;
- else if (EQ (keysym, QKbackspace)) /* backspace => c-h */
- MACROLET (make_number ('h'), (modifiers | MOD_CONTROL));
- else if (EQ (keysym, QKtab)) /* tab => c-i */
- MACROLET (make_number ('i'), (modifiers | MOD_CONTROL));
- else if (EQ (keysym, QKlinefeed)) /* linefeed => c-j */
- MACROLET (make_number ('j'), (modifiers | MOD_CONTROL));
- else if (EQ (keysym, QKreturn)) /* return => c-m */
- MACROLET (make_number ('m'), (modifiers | MOD_CONTROL));
- else if (EQ (keysym, QKescape)) /* escape => c-[ */
- MACROLET (make_number ('['), (modifiers | MOD_CONTROL));
- else
- return;
- #undef MACROLET
- }
-
-
- static void
- ensure_meta_prefix_char_keymapp (Lisp_Object keys, int index,
- Lisp_Object keymap)
- {
- /* This function can GC */
- char buf [255];
- Lisp_Object new_keys;
- int i;
- Lisp_Object mpc_binding;
- struct key_data meta_key;
-
- if (NILP (Vmeta_prefix_char) ||
- (INTP (Vmeta_prefix_char) && XINT (Vmeta_prefix_char) < 0))
- return;
-
- define_key_parser (Vmeta_prefix_char, &meta_key);
- mpc_binding = keymap_lookup_1 (keymap, &meta_key, 0);
- if (NILP (mpc_binding) || !NILP (Fkeymapp (mpc_binding)))
- return;
-
- if (index == 0)
- new_keys = keys;
- else if (STRINGP (keys))
- new_keys = Fsubstring (keys, Qzero, make_number (index));
- else if (VECTORP (keys))
- {
- new_keys = make_vector (index, Qnil);
- for (i = 0; i < index; i++)
- vector_data (XVECTOR (new_keys)) [i] =
- vector_data (XVECTOR (keys)) [i];
- }
- else
- abort ();
- if (EQ (keys, new_keys))
- sprintf (buf, GETTEXT ("can't bind %s: %s has a non-keymap binding"),
- (char *) string_data (XSTRING (Fkey_description (keys))),
- (char *) string_data (XSTRING
- (Fsingle_key_description
- (Vmeta_prefix_char))));
- else
- sprintf (buf, GETTEXT ("can't bind %s: %s %s has a non-keymap binding"),
- (char *) string_data (XSTRING (Fkey_description (keys))),
- (char *) string_data (XSTRING (Fkey_description (new_keys))),
- (char *) string_data (XSTRING
- (Fsingle_key_description
- (Vmeta_prefix_char))));
- signal_simple_error (buf, mpc_binding);
- }
-
- DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
- "Define key sequence KEYS, in KEYMAP, as DEF.\n\
- KEYMAP is a keymap object.\n\
- KEYS is the sequence of keystrokes to bind, described below.\n\
- DEF is anything that can be a key's definition:\n\
- nil (means key is undefined in this keymap);\n\
- a command (a Lisp function suitable for interactive calling);\n\
- a string or key sequence vector (treated as a keyboard macro);\n\
- a keymap (to define a prefix key);\n\
- a symbol; when the key is looked up, the symbol will stand for its\n\
- function definition, that should at that time be one of the above,\n\
- or another symbol whose function definition is used, and so on.\n\
- a cons (STRING . DEFN), meaning that DEFN is the definition\n\
- (DEFN should be a valid definition in its own right);\n\
- or a cons (KEYMAP . CHAR), meaning use definition of CHAR in map KEYMAP.\n\
- \n\
- Contrary to popular belief, the world is not ASCII. When running under a\n\
- window manager, Emacs can tell the difference between, for example, the\n\
- keystrokes control-h, control-shift-h, and backspace. You can, in fact,\n\
- bind different commands to each of these.\n\
- \n\
- A `key sequence' is a set of keystrokes. A `keystroke' is a keysym and some\n\
- set of modifiers (such as control and meta). A `keysym' is what is printed\n\
- on the keys on your keyboard.\n\
- \n\
- A keysym may be represented by a symbol, or (if and only if it is equivalent\n\
- to an ASCII character in the range 32 - 255) by its ASCII code. The `A' key\n\
- may be represented by the symbol `A' or by the number 65. The `break' key\n\
- may be represented only by the symbol `break'.\n\
- \n\
- A keystroke may be represented by a list: the last element of the list is\n\
- the key (a symbol or number, as above) and the preceding elements are the\n\
- symbolic names of modifier keys (control, meta, super, hyper, alt, and shift).\n\
- Thus, the sequence control-b is represented by the forms `(control b)' \n\
- and `(control 98)'. A keystroke may also be represented by an event object,\n\
- as returned by the `next-command-event' and `read-key-sequence' functions.\n\
- \n\
- Note that in this context, the keystroke `control-b' is *not* represented\n\
- by the number 2 (the ASCII code for ^B). See below.\n\
- \n\
- The `shift' modifier is somewhat of a special case. You should not (and\n\
- cannot) use `(meta shift a)' to mean `(meta A)', since for characters that\n\
- have ASCII equivalents, the state of the shift key is implicit in the\n\
- keysym (a vs. A). You also cannot say `(shift =)' to mean `+', as that\n\
- sort of thing varies from keyboard to keyboard. The shift modifier is for\n\
- use only with characters that do not have a second keysym on the same key,\n\
- such as `backspace' and `tab'.\n\
- \n\
- A key sequence is a vector of keystrokes. As a degenerate case, elements\n\
- of this vector may also be keysyms if they have no modifiers. That is,\n\
- the `A' keystroke is represented by all of these forms:\n\
- A 65 (A) (65) [A] [65] [(A)] [(65)]\n\
- the `control-a' keystroke is represented by these forms:\n\
- (control A) (control 65) [(control A)] [(control 65)]\n\
- the key sequence `control-c control-a' is represented by these forms:\n\
- [(control c) (control a)] [(control 99) (control 65)]\n\
- \n\
- Mouse button clicks work just like keypresses: (control button1) means\n\
- pressing the left mouse button while holding down the control key.\n\
- [(control c) (shift button3)] means control-c, hold shift, click right.\n\
- \n\
- Commands may be bound to the mouse-button up-stroke rather than the down-\n\
- stroke as well. `button1' means the down-stroke, and `button1up' means the\n\
- up-stroke. Different commands may be bound to the up and down strokes,\n\
- though that is probably not what you want, so be careful.\n\
- \n\
- For backward compatibility, a key sequence may also be represented by a\n\
- string. In this case, it represents the key sequence(s) that would\n\
- produce that sequence of ASCII characters in a purely ASCII world. For\n\
- example, a string containing the ASCII backspace character, \"\\^H\", would\n\
- represent two key sequences: `(control h)' and `backspace'. Binding a\n\
- command to this will actually bind both of those key sequences. Likewise\n\
- for the following pairs:\n\
- \n\
- control h backspace\n\
- control i tab\n\
- control m return\n\
- control j linefeed\n\
- control [ escape\n\
- control @ control space\n\
- \n\
- After binding a command to two key sequences with a form like\n\
- \n\
- (define-key global-map \"\\^X\\^I\" \'command-1)\n\
- \n\
- it is possible to redefine only one of those sequences like so:\n\
- \n\
- (define-key global-map [(control x) (control i)] \'command-2)\n\
- (define-key global-map [(control x) tab] \'command-3)\n\
- \n\
- Of course, all of this applies only when running under a window system. If\n\
- you're talking to emacs through an ASCII-only channel, you don't get any of\n\
- these features.")
- (keymap, keys, def)
- Lisp_Object keymap;
- Lisp_Object keys;
- Lisp_Object def;
- {
- /* This function can GC */
- int idx;
- int metized = 0;
- int size;
- int ascii_hack;
- struct gcpro gcpro1, gcpro2, gcpro3;
-
- if (VECTORP (keys))
- size = vector_length (XVECTOR (keys));
- else if (STRINGP (keys))
- size = string_length (XSTRING (keys));
- else if (INTP (keys) || SYMBOLP (keys) || CONSP (keys))
- {
- if (!CONSP (keys)) keys = list1 (keys);
- size = 1;
- keys = make_vector (1, keys); /* this is kinda sleazy. */
- }
- else
- {
- keys = wrong_type_argument (Qsequencep, keys);
- size = XINT (Flength (keys));
- }
- if (size == 0)
- return (Qnil);
-
- GCPRO3 (keymap, keys, def);
-
- /* ASCII grunge.
- When the user defines a key which, in a strictly ASCII world, would be
- produced by two different keys (^J and linefeed, or ^H and backspace,
- for example) then the binding will be made for both keysyms.
-
- This is done if the user binds a command to a string, as in
- (define-key map "\^H" 'something), but not when using one of the new
- syntaxes, like (define-key map '(control h) 'something).
- */
- ascii_hack = (STRINGP (keys));
-
- keymap = get_keymap (keymap, 1, 1);
-
- idx = 0;
- while (1)
- {
- Lisp_Object c;
- struct key_data raw_key1;
- struct key_data raw_key2;
-
- if (STRINGP (keys))
- c = make_number (string_char (XSTRING (keys), idx));
- else
- {
- c = vector_data (XVECTOR (keys)) [idx];
- if (INTP (c) &&
- (XINT (c) < ' ' || XINT (c) > 127))
- args_out_of_range_3 (c, make_number (32), make_number (127));
- }
-
- define_key_parser (c, &raw_key1);
-
- if (!metized && ascii_hack && meta_prefix_char_p (&raw_key1))
- {
- if (idx == (size - 1))
- {
- /* This is a hack to prevent a binding for the meta-prefix-char
- from being made in a map which already has a non-empty "meta"
- submap. That is, we can't let both "escape" and "meta" have
- a binding in the same keymap. This implies that the idiom
- (define-key my-map "\e" my-escape-map)
- (define-key my-escape-map "a" 'my-command)
- no longer works. That's ok. Instead the luser should do
- (define-key my-map "\ea" 'my-command)
- or, more correctly
- (define-key my-map "\M-a" 'my-command)
- and then perhaps
- (defvar my-escape-map (lookup-key my-map "\e"))
- if the luser really wants the map in a variable.
- */
- Lisp_Object mmap;
- struct gcpro gcpro1;
-
- GCPRO1 (c);
- mmap = Fgethash (MAKE_MODIFIER_HASH_KEY (MOD_META),
- XKEYMAP (keymap)->table, Qnil);
- if (!NILP (mmap)
- && keymap_fullness (mmap) != 0)
- {
- Lisp_Object desc
- = Fsingle_key_description (Vmeta_prefix_char);
- signal_simple_error_2
- ("Map contains meta-bindings, can't bind", desc, keymap);
- }
- UNGCPRO;
- }
- else
- {
- metized = 1;
- idx++;
- continue;
- }
- }
-
- if (ascii_hack)
- define_key_alternate_name (&raw_key1, &raw_key2);
- else
- {
- raw_key2.keysym = Qnil;
- raw_key2.modifiers = 0;
- }
-
- if (metized)
- {
- raw_key1.modifiers |= MOD_META;
- raw_key2.modifiers |= MOD_META;
- metized = 0;
- }
-
- /* This crap is to make sure that someone doesn't bind something like
- "C-x M-a" while "C-x ESC" has a non-keymap binding. */
- if (raw_key1.modifiers & MOD_META)
- ensure_meta_prefix_char_keymapp (keys, idx, keymap);
-
- if (++idx == size)
- {
- keymap_store (keymap, &raw_key1, def);
- if (ascii_hack && !NILP (raw_key2.keysym))
- keymap_store (keymap, &raw_key2, def);
- UNGCPRO;
- return def;
- }
-
- {
- Lisp_Object cmd;
- struct gcpro gcpro1;
- GCPRO1 (c);
-
- cmd = keymap_lookup_1 (keymap, &raw_key1, 0);
- if (NILP (cmd))
- {
- cmd = Fmake_sparse_keymap ();
- XKEYMAP (cmd)->name /* for debugging */
- = list2 (make_key_description (&raw_key1, 1), keymap);
- keymap_store (keymap, &raw_key1, cmd);
- }
- if (NILP (Fkeymapp (cmd)))
- signal_simple_error_2 ("invalid prefix keys in sequence",
- c, keys);
-
- if (ascii_hack && !NILP (raw_key2.keysym) &&
- NILP (keymap_lookup_1 (keymap, &raw_key2, 0)))
- keymap_store (keymap, &raw_key2, cmd);
-
- keymap = get_keymap (cmd, 1, 1);
- UNGCPRO;
- }
- }
- }
-
-
- /************************************************************************/
- /* Looking up keys in keymaps */
- /************************************************************************/
-
- /* We need a very fast (i.e., non-consing) version of lookup-key in order
- to make where-is-internal really fly.
- */
-
- struct raw_lookup_key_mapper_closure
- {
- int remaining;
- CONST struct key_data *raw_keys;
- int raw_keys_count;
- int keys_so_far;
- int accept_default;
- };
-
- static Lisp_Object raw_lookup_key_mapper (Lisp_Object k, void *);
-
- /* Caller should gc-protect args (keymaps may autoload) */
- static Lisp_Object
- raw_lookup_key (Lisp_Object keymap,
- CONST struct key_data *raw_keys, int raw_keys_count,
- int keys_so_far, int accept_default)
- {
- /* This function can GC */
- struct raw_lookup_key_mapper_closure c;
- c.remaining = raw_keys_count - 1;
- c.raw_keys = raw_keys;
- c.raw_keys_count = raw_keys_count;
- c.keys_so_far = keys_so_far;
- c.accept_default = accept_default;
-
- return (traverse_keymaps (keymap, Qnil, raw_lookup_key_mapper,
- &c));
- }
-
- static Lisp_Object
- raw_lookup_key_mapper (Lisp_Object k, void *arg)
- {
- /* This function can GC */
- struct raw_lookup_key_mapper_closure *c = arg;
- int accept_default = c->accept_default;
- int remaining = c->remaining;
- int keys_so_far = c->keys_so_far;
- CONST struct key_data *raw_keys = c->raw_keys;
- Lisp_Object cmd;
-
- if (! meta_prefix_char_p (&(raw_keys[0])))
- {
- /* Normal case: every case except the meta-hack (see below). */
- cmd = keymap_lookup_1 (k, &(raw_keys[0]), accept_default);
-
- if (remaining == 0)
- /* Return whatever we found if we're out of keys */
- ;
- else if (NILP (cmd))
- /* Found nothing (though perhaps parent map may have binding) */
- ;
- else if (NILP (Fkeymapp (cmd)))
- /* Didn't find a keymap, and we have more keys.
- * Return a fixnum to indicate that keys were too long.
- */
- cmd = make_number (keys_so_far + 1);
- else
- cmd = raw_lookup_key (cmd, raw_keys + 1, remaining,
- keys_so_far + 1, accept_default);
- }
- else
- {
- /* This is a hack so that looking up a key-sequence whose last
- * element is the meta-prefix-char will return the keymap that
- * the "meta" keys are stored in, if there is no binding for
- * the meta-prefix-char (and if this map has a "meta" submap).
- * If this map doesnt have a "meta" submap, then the
- * meta-prefix-char is looked up just like any other key.
- */
- if (remaining == 0)
- {
- /* First look for the prefix-char directly */
- cmd = keymap_lookup_1 (k, &(raw_keys[0]), accept_default);
- if (NILP (cmd))
- {
- /* Do kludgy return of the meta-map */
- cmd = Fgethash (MAKE_MODIFIER_HASH_KEY (MOD_META),
- XKEYMAP (k)->table, Qnil);
- }
- }
- else
- {
- /* Search for the prefix-char-prefixed sequence directly */
- cmd = keymap_lookup_1 (k, &(raw_keys[0]), accept_default);
- cmd = get_keymap (cmd, 0, 1);
- if (!NILP (cmd))
- cmd = raw_lookup_key (cmd, raw_keys + 1, remaining,
- keys_so_far + 1, accept_default);
- else if ((raw_keys[1].modifiers & MOD_META) == 0)
- {
- struct key_data metified;
- metified.keysym = raw_keys[1].keysym;
- metified.modifiers = raw_keys[1].modifiers | MOD_META;
-
- /* Search for meta-next-char sequence directly */
- cmd = keymap_lookup_1 (k, &metified, accept_default);
- if (remaining == 1)
- ;
- else
- {
- cmd = get_keymap (cmd, 0, 1);
- if (!NILP (cmd))
- cmd = raw_lookup_key (cmd, raw_keys + 2, remaining - 1,
- keys_so_far + 2,
- accept_default);
- }
- }
- }
- }
- if (accept_default && NILP (cmd))
- cmd = XKEYMAP (k)->default_binding;
- return (cmd);
- }
-
- /* Value is number if `keys' is too long; NIL if valid but has no definition.*/
- /* Caller should gc-protect arguments */
- static Lisp_Object
- lookup_keys (Lisp_Object keymap, int nkeys, Lisp_Object *keys,
- int accept_default)
- {
- /* This function can GC */
- struct key_data kkk[20];
- struct key_data *raw_keys;
- int i;
-
- if (nkeys == 0)
- return Qnil;
-
- if (nkeys > (countof (kkk)))
- raw_keys = kkk;
- else
- raw_keys = (struct key_data *) alloca (sizeof (struct key_data) * nkeys);
-
- for (i = 0; i < nkeys; i++)
- {
- define_key_parser (keys[i], &(raw_keys[i]));
- }
- return (raw_lookup_key (keymap, raw_keys, nkeys, 0,
- accept_default));
- }
-
- static Lisp_Object
- lookup_events (Lisp_Object event_head, int nmaps, Lisp_Object keymaps[],
- int accept_default)
- {
- /* This function can GC */
- struct key_data kkk[20];
-
- int nkeys;
- struct key_data *raw_keys;
- struct Lisp_Event *e;
- Lisp_Object tem = Qnil;
- struct gcpro gcpro1, gcpro2;
- int iii;
-
- CHECK_LIVE_EVENT (event_head, 0);
-
- for (e = XEVENT (event_head), nkeys = 0; e; e = event_next (e), nkeys++)
- ;
-
- if (nkeys < (countof (kkk)))
- raw_keys = kkk;
- else
- raw_keys = (struct key_data *) alloca (sizeof (struct key_data) * nkeys);
-
- for (e = XEVENT (event_head), nkeys = 0; e; e = event_next (e), nkeys++)
- {
- Lisp_Object c = Qnil;
-
- XSETEVENT (c, e);
- define_key_parser (c, &(raw_keys[nkeys]));
- }
- GCPRO2 (keymaps[0], event_head);
- gcpro1.nvars = nmaps;
- /* ####raw_keys[].keysym slots aren't gc-protected. We rely (but shouldn't)
- * on somebody else somewhere (obarray) having a pointer to all keysyms. */
- for (iii = 0; iii < nmaps; iii++)
- {
- tem = raw_lookup_key (keymaps[iii], raw_keys, nkeys, 0,
- accept_default);
- if (INTP (tem))
- {
- /* Too long in some local map means don't look at global map */
- tem = Qnil;
- break;
- }
- else if (!NILP (tem))
- break;
- }
- UNGCPRO;
- return (tem);
- }
-
- DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
- "In keymap KEYMAP, look up key-sequence KEYS. Return the definition.\n\
- Nil is returned if KEYS is unbound. See documentation of `define-key'\n\
- for valid key definitions and key-sequence specifications.\n\
- A number is returned if KEYS is \"too long\"; that is, the leading\n\
- characters fail to be a valid sequence of prefix characters in KEYMAP.\n\
- The number is how many characters at the front of KEYS\n\
- it takes to reach a non-prefix command.")
- (keymap, keys, accept_default)
- Lisp_Object keymap, keys, accept_default;
- {
- /* This function can GC */
- if (VECTORP (keys))
- {
- return lookup_keys (keymap,
- vector_length (XVECTOR (keys)),
- vector_data (XVECTOR (keys)),
- !NILP (accept_default));
- }
- else if (SYMBOLP (keys) || INTP (keys) || CONSP (keys))
- {
- return lookup_keys (keymap, 1, &keys,
- !NILP (accept_default));
- }
- else if (!STRINGP (keys))
- {
- keys = wrong_type_argument (Qsequencep, keys);
- return Flookup_key (keymap, keys, accept_default);
- }
- else
- {
- int length = string_length (XSTRING (keys));
- int i;
- struct key_data *raw_keys
- = (struct key_data *) alloca (sizeof (struct key_data) * length);
- if (length == 0)
- return Qnil;
-
- for (i = 0; i < length; i++)
- {
- unsigned char n = (unsigned char) string_char (XSTRING (keys), i);
- define_key_parser (make_number (n), &(raw_keys[i]));
- }
- return (raw_lookup_key (keymap, raw_keys, length, 0,
- !NILP (accept_default)));
- }
- }
-
- /* Given a key sequence, returns a list of keymaps to search for bindings.
- Does all manner of semi-hairy heuristics, like looking in the current
- buffer's map before looking in the global map and looking in the local
- map of the buffer in which the mouse was clicked in event0 is a click.
-
- It would be kind of nice if this were in Lisp so that this semi-hairy
- semi-heuristic command-lookup behaviour could be readily understood and
- customised. However, this needs to be pretty fast, or performance of
- keyboard macros goes to shit; putting this in lisp slows macros down
- 2-3x. And they're already slower than v18 by 5-6x.
- */
-
- struct relevant_maps
- {
- int nmaps;
- unsigned int max_maps;
- Lisp_Object *maps;
- struct gcpro *gcpro;
- };
-
- static void get_relevant_extent_keymaps (Lisp_Object pos,
- Lisp_Object buffer,
- Lisp_Object glyph,
- struct relevant_maps *closure);
- static void get_relevant_minor_maps (Lisp_Object buffer,
- struct relevant_maps *closure);
-
- static void
- relevant_map_push (Lisp_Object map, struct relevant_maps *closure)
- {
- unsigned int nmaps = closure->nmaps;
-
- if (!KEYMAPP (map))
- return;
- closure->nmaps = nmaps + 1;
- if (nmaps < closure->max_maps)
- {
- closure->maps[nmaps] = map;
- closure->gcpro->nvars = nmaps;
- }
- }
-
- static int
- get_relevant_keymaps (Lisp_Object keys,
- int max_maps, Lisp_Object maps[])
- {
- /* This function can GC */
- Lisp_Object terminal = Qnil;
- struct gcpro gcpro1;
- struct relevant_maps closure;
-
- GCPRO1 (*maps);
- gcpro1.nvars = 0;
- closure.nmaps = 0;
- closure.max_maps = max_maps;
- closure.maps = maps;
- closure.gcpro = &gcpro1;
-
- if (EVENTP (keys))
- {
- struct Lisp_Event *e = XEVENT (keys);
- for (e = XEVENT (keys);
- event_next (e);
- e = event_next (e))
- ;
- XSETEVENT (terminal, e);
- }
- else if (VECTORP (keys))
- {
- int len = vector_length (XVECTOR (keys));
- if (len > 1)
- terminal = vector_data (XVECTOR (keys))[len - 1];
- }
-
- if (KEYMAPP (Voverriding_local_map))
- {
- relevant_map_push (Voverriding_local_map, &closure);
- }
- else if (!EVENTP (terminal)
- || (XEVENT (terminal)->event_type != button_press_event
- && XEVENT (terminal)->event_type != button_release_event))
- {
- Lisp_Object tem;
- XSETBUFFER (tem, current_buffer);
- /* It's not a mouse event; order of keymaps searched is:
- o keymap of any/all extents under the mouse
- o minor-mode maps
- o local-map of current-buffer
- o global-map
- */
- /* The terminal element of the lookup may be nil or a keysym.
- In those cases we don't want to check for an extent
- keymap. */
- if (EVENTP (terminal))
- {
- get_relevant_extent_keymaps (make_number (BUF_PT (current_buffer)),
- tem, Qnil, &closure);
- }
- get_relevant_minor_maps (tem, &closure);
-
- tem = current_buffer->keymap;
- if (!NILP (tem))
- relevant_map_push (tem, &closure);
- }
- #ifdef HAVE_WINDOW_SYSTEM
- else
- {
- /* It's a mouse event; order of keymaps searched is:
- o local-map of mouse-grabbed-buffer
- o keymap of any/all extents under the mouse
- if the mouse is over a modeline:
- o modeline-map of buffer corresponding to that modeline
- o else, local-map of buffer under the mouse
- o minor-mode maps
- o local-map of current-buffer
- o global-map
- */
- Lisp_Object window = Fevent_window (terminal);
-
- if (BUFFERP (Vmouse_grabbed_buffer))
- {
- Lisp_Object map = XBUFFER (Vmouse_grabbed_buffer)->keymap;
-
- get_relevant_minor_maps (Vmouse_grabbed_buffer, &closure);
- if (!NILP (map))
- relevant_map_push (map, &closure);
- }
-
- if (!NILP (window))
- {
- Lisp_Object buffer = Fwindow_buffer (window);
-
- if (!NILP (buffer))
- {
- if (!NILP (Fevent_over_modeline_p (terminal)))
- {
- Lisp_Object map = symbol_value_in_buffer (Qmodeline_map,
- buffer);
-
- if (!EQ (map, Qunbound) && !NILP (map))
- relevant_map_push (map, &closure);
- }
- else
- {
- /* if it was a modeline hit, then it can't have been over
- an extent with a keymap. */
- get_relevant_extent_keymaps (Fevent_point (terminal), buffer,
- Fevent_glyph_extent (terminal),
- &closure);
- }
-
- if (!EQ (buffer, Vmouse_grabbed_buffer)) /* already pushed */
- {
- get_relevant_minor_maps (buffer, &closure);
- relevant_map_push (XBUFFER (buffer)->keymap, &closure);
- }
- }
- }
- else if (!NILP (Fevent_over_toolbar_p (terminal)))
- {
- Lisp_Object map = Fsymbol_value (Qtoolbar_map);
-
- if (!EQ (map, Qunbound) && !NILP (map))
- relevant_map_push (map, &closure);
- }
- }
- #endif /* HAVE_WINDOW_SYSTEM */
-
- {
- int nmaps = closure.nmaps;
- /* Silently truncate at 100 keymaps to prevent infinite losssage */
- if (nmaps >= max_maps && max_maps > 0)
- maps[max_maps - 1] = Vcurrent_global_map;
- else
- maps[nmaps] = Vcurrent_global_map;
- UNGCPRO;
- return (nmaps + 1);
- }
- }
-
- /* Returns a set of keymaps extracted from the extents at POS in BUFFER.
- The GLYPH arg, if specified, is one more extent to look for a keymap in,
- and if it has one, its keymap will be the first element in the list
- returned. This is so we can correctly search the keymaps associated
- with glyphs which may be physically disjoint from their extents: for
- example, if a glyph is out in the margin, we should still consult the
- kemyap of that glyph's extent, which may not itself be under the mouse.
- */
- static void
- get_relevant_extent_keymaps (Lisp_Object pos, Lisp_Object buffer,
- Lisp_Object glyph,
- struct relevant_maps *closure)
- {
- /* This function can GC */
- /* the glyph keymap, if any, comes first.
- (Processing it twice is no big deal: noop.) */
- if (!NILP (glyph))
- {
- Lisp_Object keymap = Fextent_property (glyph, Qkeymap);
- if (!NILP (keymap))
- relevant_map_push (get_keymap (keymap, 1, 1), closure);
- }
-
- /* Next check the extents at the text position, if any */
- if (!NILP (pos))
- {
- Lisp_Object extent;
- for (extent = Fextent_at (pos, buffer, Qkeymap, Qnil);
- !NILP (extent);
- extent = Fextent_at (pos, buffer, Qkeymap, extent))
- {
- Lisp_Object keymap = Fextent_property (extent, Qkeymap);
- if (!NILP (keymap))
- relevant_map_push (get_keymap (keymap, 1, 1), closure);
- QUIT;
- }
- }
- }
-
- static Lisp_Object
- minor_mode_keymap_predicate (Lisp_Object assoc, Lisp_Object buffer)
- {
- /* This function can GC */
- if (CONSP (assoc))
- {
- Lisp_Object sym = XCAR (assoc);
- if (SYMBOLP (sym))
- {
- Lisp_Object val = symbol_value_in_buffer (sym, buffer);
- if (!EQ (val, Qnil) && !EQ (val, Qunbound))
- {
- Lisp_Object map = get_keymap (XCDR (assoc), 0, 1);
- return (map);
- }
- }
- }
- return (Qnil);
- }
-
- static void
- get_relevant_minor_maps (Lisp_Object buffer, struct relevant_maps *closure)
- {
- /* This function can GC */
- Lisp_Object alist;
-
- /* Will you ever lose badly if you make this circular! */
- for (alist = symbol_value_in_buffer (Qminor_mode_map_alist, buffer);
- CONSP (alist);
- alist = XCDR (alist))
- {
- Lisp_Object m = minor_mode_keymap_predicate (XCAR (alist),
- buffer);
- if (!NILP (m)) relevant_map_push (m, closure);
- QUIT;
- }
- }
-
- /* #### Would map-current-keymaps be a better thing?? */
- DEFUN ("current-keymaps", Fcurrent_keymaps, Scurrent_keymaps, 0, 1, 0,
- "Return a list of the current keymaps that will be searched for bindings.\n\
- This lists keymaps such as the current local map and the minor-mode maps,\n\
- but does not list the parents of those keymaps.\n\
- EVENT-OR-KEYS controls which keymaps will be listed.\n\
- If EVENT-OR-KEYS is a mouse event (or a vector whose last element is a\n\
- mouse event), the keymaps for that mouse event will be listed (see\n\
- `key-binding'). Otherwise, the keymaps for key presses will be listed.")
- (event_or_keys)
- Lisp_Object event_or_keys;
- {
- /* This function can GC */
- struct gcpro gcpro1;
- Lisp_Object maps[100];
- Lisp_Object *gubbish = maps;
- int nmaps;
-
- GCPRO1 (event_or_keys);
- nmaps = get_relevant_keymaps (event_or_keys, countof (maps),
- gubbish);
- if (nmaps > countof (maps))
- {
- gubbish = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- nmaps = get_relevant_keymaps (event_or_keys, nmaps, gubbish);
- }
- UNGCPRO;
- return (Flist (nmaps, gubbish));
- }
-
- DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 2, 0,
- "Return the binding for command KEYS in current keymaps.\n\
- KEYS is a string, a vector of events, or a vector of key-description lists\n\
- as described in the documentation for the `define-key' function.\n\
- The binding is probably a symbol with a function definition; see\n\
- the documentation for `lookup-key' for more information.\n\
- \n\
- For key-presses, the order of keymaps searched is:\n\
- - the `keymap' property of any extent(s) at point;\n\
- - any applicable minor-mode maps;\n\
- - the current-local-map of the current-buffer;\n\
- - the current global map.\n\
- \n\
- For mouse-clicks, the order of keymaps searched is:\n\
- - the current-local-map of the `mouse-grabbed-buffer' if any;\n\
- - the `keymap' property of any extent(s) at the position of the click;\n\
- - the modeline-map of the buffer corresponding to the modeline under\n\
- the mouse (if the click happened over a modeline);\n\
- - the current-local-map of the buffer under the mouse;\n\
- - any applicable minor-mode maps;\n\
- - the current global map.\n\
- \n\
- Note that if `overriding-local-map' is non-nil, *only* it and the current\n\
- global map are searched.")
- (keys, accept_default)
- Lisp_Object keys, accept_default;
- {
- /* This function can GC */
- int i;
- Lisp_Object maps[100];
- int nmaps;
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (keys, accept_default); /* get_relevant_keymaps may autoload */
-
- nmaps = get_relevant_keymaps (keys, countof (maps), maps);
-
- UNGCPRO;
-
- if (EVENTP (keys)) /* unadvertised "feature" for the future */
- return (lookup_events (keys, nmaps, maps,
- !NILP (accept_default)));
-
- for (i = 0; i < nmaps; i++)
- {
- Lisp_Object tem = Flookup_key (maps[i], keys,
- accept_default);
- if (INTP (tem))
- {
- /* Too long in some local map means don't look at global map */
- return (Qnil);
- }
- else if (!NILP (tem))
- return (tem);
- }
- return (Qnil);
- }
-
- /* Attempts to find a command corresponding to the event-sequence
- whose head is event0 (sequence is threaded though event_next).
- Returns either a command symbol or Qnil.
- */
- Lisp_Object
- event_binding (Lisp_Object event0, int accept_default)
- {
- /* This function can GC */
- Lisp_Object maps[100];
- int nmaps;
-
- if (!EVENTP (event0)) abort ();
-
- nmaps = get_relevant_keymaps (event0, countof (maps), maps);
- return (lookup_events (event0, nmaps, maps, accept_default));
- }
-
- /* Attempts to find a function key mapping corresponding to the
- event-sequence whose head is event0 (sequence is threaded through
- event_next). Returns either a command symbol or Qnil. */
- Lisp_Object
- function_key_map_event_binding (Lisp_Object event0)
- {
- struct device *d = XDEVICE (EVENT_DEVICE (XEVENT (event0)));
- Lisp_Object maps[1];
-
- if (NILP (DEVICE_FUNCTION_KEY_MAP (d)))
- return Qnil;
-
- maps[0] = DEVICE_FUNCTION_KEY_MAP (d);
- return (lookup_events (event0, 1, maps, 1));
- }
-
-
- /************************************************************************/
- /* Setting/querying the global and local maps */
- /************************************************************************/
-
- DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0,
- "Select KEYMAP as the global keymap.")
- (keymap)
- Lisp_Object keymap;
- {
- /* This function can GC */
- keymap = get_keymap (keymap, 1, 1);
- Vcurrent_global_map = keymap;
- return Qnil;
- }
-
- DEFUN ("use-local-map", Fuse_local_map, Suse_local_map, 1, 2, 0,
- "Select KEYMAP as the local keymap in BUFFER.\n\
- If KEYMAP is nil, that means no local keymap.\n\
- If BUFFER is nil, the current buffer is assumed.")
- (keymap, buffer)
- Lisp_Object keymap, buffer;
- {
- /* This function can GC */
- struct buffer *b = decode_buffer (buffer, 0);
- if (!NILP (keymap))
- keymap = get_keymap (keymap, 1, 1);
-
- b->keymap = keymap;
-
- return Qnil;
- }
-
- DEFUN ("current-local-map", Fcurrent_local_map, Scurrent_local_map, 0, 1, 0,
- "Return BUFFER's local keymap, or nil if it has none.\n\
- If BUFFER is nil, the current buffer is assumed.")
- (buffer)
- Lisp_Object buffer;
- {
- struct buffer *b = decode_buffer (buffer, 0);
- return b->keymap;
- }
-
- DEFUN ("current-global-map", Fcurrent_global_map, Scurrent_global_map, 0, 0, 0,
- "Return the current global keymap.")
- ()
- {
- return (Vcurrent_global_map);
- }
-
-
- /************************************************************************/
- /* Mapping over keymap elements */
- /************************************************************************/
-
- /* Since keymaps are arranged in a hierarchy, one keymap per bucky bit or
- prefix key, it's not entirely objvious what map-keymap should do, but
- what it does is: map over all keys in this map; then recursively map
- over all submaps of this map that are "bucky" submaps. This means that,
- when mapping over a keymap, it appears that "x" and "C-x" are in the
- same map, although "C-x" is really in the "control" submap of this one.
- However, since we don't recursively descend the submaps that are bound
- to prefix keys (like C-x, C-h, etc) the caller will have to recurse on
- those explicitly, if that's what they want.
-
- So the end result of this is that the bucky keymaps (the ones indexed
- under the large integers returned from MAKE_MODIFIER_HASH_KEY()) are
- invisible from elisp. They're just an implementation detail that code
- outside of this file doesn't need to know about.
- */
-
- struct map_keymap_unsorted_closure
- {
- void (*fn) (CONST struct key_data *, Lisp_Object binding, void *arg);
- void *arg;
- unsigned int modifiers;
- };
-
- /* used by map_keymap() */
- static void
- map_keymap_unsorted_mapper (CONST void *hash_key, void *hash_contents,
- void *map_keymap_unsorted_closure)
- {
- /* This function can GC */
- Lisp_Object keysym;
- Lisp_Object contents;
- struct map_keymap_unsorted_closure *closure = map_keymap_unsorted_closure;
- unsigned int modifiers = closure->modifiers;
- unsigned int mod_bit;
- CVOID_TO_LISP (keysym, hash_key);
- VOID_TO_LISP (contents, hash_contents);
- mod_bit = MODIFIER_HASH_KEY_P (keysym);
- if (mod_bit != 0)
- {
- int omod = modifiers;
- closure->modifiers = (modifiers | mod_bit);
- contents = get_keymap (contents, 1, 1);
- elisp_maphash (map_keymap_unsorted_mapper,
- XKEYMAP (contents)->table,
- map_keymap_unsorted_closure);
- closure->modifiers = omod;
- }
- else
- {
- struct key_data key;
- key.keysym = keysym;
- key.modifiers = modifiers;
- ((*closure->fn) (&key, contents, closure->arg));
- }
- }
-
-
- struct map_keymap_sorted_closure
- {
- Lisp_Object *result_locative;
- };
-
- /* used by map_keymap_sorted() */
- static void
- map_keymap_sorted_mapper (CONST void *hash_key, void *hash_contents,
- void *map_keymap_sorted_closure)
- {
- struct map_keymap_sorted_closure *cl = map_keymap_sorted_closure;
- Lisp_Object key, contents;
- Lisp_Object *list = cl->result_locative;
- CVOID_TO_LISP (key, hash_key);
- VOID_TO_LISP (contents, hash_contents);
- *list = Fcons (Fcons (key, contents), *list);
- }
-
-
- /* used by map_keymap_sorted(), describe_map_sort_predicate(),
- and keymap_submaps().
- */
- static int
- map_keymap_sort_predicate (Lisp_Object obj1, Lisp_Object obj2,
- Lisp_Object pred)
- {
- /* obj1 and obj2 are conses with keysyms in their cars. Cdrs are ignored.
- */
- unsigned int bit1, bit2;
- int sym1_p = 0;
- int sym2_p = 0;
- obj1 = XCAR (obj1);
- obj2 = XCAR (obj2);
-
- if (EQ (obj1, obj2))
- return -1;
- bit1 = MODIFIER_HASH_KEY_P (obj1);
- bit2 = MODIFIER_HASH_KEY_P (obj2);
-
- /* If either is a symbol with a character-set-property, then sort it by
- that code instead of alphabetically.
- */
- if (! bit1 && SYMBOLP (obj1))
- {
- Lisp_Object code = Fget (obj1, Vcharacter_set_property, Qnil);
- if (INTP (code))
- obj1 = code, sym1_p = 1;
- }
- if (! bit2 && SYMBOLP (obj2))
- {
- Lisp_Object code = Fget (obj2, Vcharacter_set_property, Qnil);
- if (INTP (code))
- obj2 = code, sym2_p = 1;
- }
-
- /* all symbols (non-ASCIIs) come after integers (ASCIIs) */
- if (XTYPE (obj1) != XTYPE (obj2))
- return ((SYMBOLP (obj2)) ? 1 : -1);
-
- if (! bit1 && INTP (obj1)) /* they're both ASCII */
- {
- int o1 = XINT (obj1);
- int o2 = XINT (obj2);
- if (o1 == o2 && /* If one started out as a symbol and the */
- sym1_p != sym2_p) /* other didn't, the symbol comes last. */
- return (sym2_p ? 1 : -1);
-
- return ((o1 < o2) ? 1 : -1); /* else just compare them */
- }
-
- /* else they're both symbols. If they're both buckys, then order them. */
- if (bit1 && bit2)
- return ((bit1 < bit2) ? 1 : -1);
-
- /* if only one is a bucky, then it comes later */
- if (bit1 || bit2)
- return (bit2 ? 1 : -1);
-
- /* otherwise, string-sort them. */
- {
- char *s1 = (char *) string_data (XSYMBOL (obj1)->name);
- char *s2 = (char *) string_data (XSYMBOL (obj2)->name);
- return (
- #ifdef I18N2
- (0 > strcoll (s1, s2))
- #else
- (0 > strcmp (s1, s2))
- #endif
- ? 1 : -1);
- }
- }
-
-
- /* used by map_keymap() */
- static void
- map_keymap_sorted (Lisp_Object keymap_table,
- unsigned int modifiers,
- void (*function) (CONST struct key_data *key,
- Lisp_Object binding,
- void *map_keymap_sorted_closure),
- void *map_keymap_sorted_closure)
- {
- /* This function can GC */
- struct gcpro gcpro1;
- Lisp_Object contents = Qnil;
-
- if (XINT (Fhashtable_fullness (keymap_table)) == 0)
- return;
-
- GCPRO1 (contents);
-
- {
- struct map_keymap_sorted_closure c1;
- c1.result_locative = &contents;
- elisp_maphash (map_keymap_sorted_mapper, keymap_table, &c1);
- }
- contents = list_sort (contents, Qnil, map_keymap_sort_predicate);
- for (; !NILP (contents); contents = XCDR (contents))
- {
- Lisp_Object keysym = XCAR (XCAR (contents));
- Lisp_Object binding = XCDR (XCAR (contents));
- unsigned int sub_bits = MODIFIER_HASH_KEY_P (keysym);
- if (sub_bits != 0)
- map_keymap_sorted (XKEYMAP (get_keymap (binding,
- 1, 1))->table,
- (modifiers | sub_bits),
- function,
- map_keymap_sorted_closure);
- else
- {
- struct key_data k;
- k.keysym = keysym;
- k.modifiers = modifiers;
- ((*function) (&k, binding, map_keymap_sorted_closure));
- }
- }
- UNGCPRO;
- }
-
-
- /* used by Fmap_keymap() */
- static void
- map_keymap_mapper (CONST struct key_data *key,
- Lisp_Object binding,
- void *function)
- {
- /* This function can GC */
- Lisp_Object fn;
- VOID_TO_LISP (fn, function);
- call2 (fn, make_key_description (key, 1), binding);
- }
-
-
- static void
- map_keymap (Lisp_Object keymap_table, int sort_first,
- void (*function) (CONST struct key_data *key,
- Lisp_Object binding,
- void *fn_arg),
- void *fn_arg)
- {
- /* This function can GC */
- if (sort_first)
- map_keymap_sorted (keymap_table, 0, function, fn_arg);
- else
- {
- struct map_keymap_unsorted_closure map_keymap_unsorted_closure;
- map_keymap_unsorted_closure.fn = function;
- map_keymap_unsorted_closure.arg = fn_arg;
- map_keymap_unsorted_closure.modifiers = 0;
- elisp_maphash (map_keymap_unsorted_mapper, keymap_table,
- &map_keymap_unsorted_closure);
- }
- }
-
- DEFUN ("map-keymap", Fmap_keymap, Smap_keymap, 2, 3, 0,
- "Apply FUNCTION to each element of KEYMAP.\n\
- FUNCTION will be called with two arguments: a key-description list, and\n\
- the binding. The order in which the elements of the keymap are passed to\n\
- the function is unspecified. If the function inserts new elements into\n\
- the keymap, it may or may not be called with them later. No element of\n\
- the keymap will ever be passed to the function more than once.\n\
- \n\
- The function will not be called on elements of this keymap's parents\n\
- (see the function `keymap-parents') or upon keymaps which are contained\n\
- within this keymap (multi-character definitions).\n\
- It will be called on \"meta\" characters since they are not really\n\
- two-character sequences.\n\
- \n\
- If the optional third argument SORT-FIRST is non-nil, then the elements of\n\
- the keymap will be passed to the mapper function in a canonical order.\n\
- Otherwise, they will be passed in hash (that is, random) order, which is\n\
- faster.")
- (function, keymap, sort_first)
- Lisp_Object function, keymap, sort_first;
- {
- /* This function can GC */
- struct gcpro gcpro1, gcpro2;
-
- /* tolerate obviously transposed args */
- if (!NILP (Fkeymapp (function)))
- {
- Lisp_Object tmp = function;
- function = keymap;
- keymap = tmp;
- }
- GCPRO2 (function, keymap);
- keymap = get_keymap (keymap, 1, 1);
- map_keymap (XKEYMAP (keymap)->table, !NILP (sort_first),
- map_keymap_mapper, LISP_TO_VOID (function));
- UNGCPRO;
- return Qnil;
- }
-
-
-
- /************************************************************************/
- /* Accessible keymaps */
- /************************************************************************/
-
- struct accessible_keymaps_closure
- {
- Lisp_Object tail;
- };
-
-
- static void
- accessible_keymaps_mapper_1 (Lisp_Object keysym, Lisp_Object contents,
- unsigned int modifiers,
- struct accessible_keymaps_closure *closure)
- {
- /* This function can GC */
- unsigned int subbits = MODIFIER_HASH_KEY_P (keysym);
-
- if (subbits != 0)
- {
- Lisp_Object submaps;
-
- contents = get_keymap (contents, 1, 1);
- submaps = keymap_submaps (contents);
- for (; !NILP (submaps); submaps = XCDR (submaps))
- {
- accessible_keymaps_mapper_1 (XCAR (XCAR (submaps)),
- XCDR (XCAR (submaps)),
- (subbits | modifiers),
- closure);
- }
- }
- else
- {
- Lisp_Object thisseq = Fcar (Fcar (closure->tail));
- Lisp_Object cmd = get_keyelt (contents, 1);
- Lisp_Object vec;
- int j;
- struct key_data key;
- key.keysym = keysym;
- key.modifiers = modifiers;
-
- if (NILP (cmd))
- abort ();
- cmd = get_keymap (cmd, 0, 1);
- if (!KEYMAPP (cmd))
- abort ();
-
- vec = make_vector (vector_length (XVECTOR (thisseq)) + 1, Qnil);
- for (j = 0; j < vector_length (XVECTOR (thisseq)); j++)
- vector_data (XVECTOR (vec)) [j] = vector_data (XVECTOR (thisseq)) [j];
- vector_data (XVECTOR (vec)) [j] = make_key_description (&key, 1);
-
- nconc2 (closure->tail, list1 (Fcons (vec, cmd)));
- }
- }
-
-
- static Lisp_Object
- accessible_keymaps_keymap_mapper (Lisp_Object thismap, void *arg)
- {
- /* This function can GC */
- struct accessible_keymaps_closure *closure = arg;
- Lisp_Object submaps = keymap_submaps (thismap);
-
- for (; !NILP (submaps); submaps = XCDR (submaps))
- {
- accessible_keymaps_mapper_1 (XCAR (XCAR (submaps)),
- XCDR (XCAR (submaps)),
- 0,
- closure);
- }
- return (Qnil);
- }
-
-
- DEFUN ("accessible-keymaps", Faccessible_keymaps, Saccessible_keymaps,
- 1, 2, 0,
- "Find all keymaps accessible via prefix characters from STARTMAP.\n\
- Returns a list of elements of the form (KEYS . MAP), where the sequence\n\
- KEYS starting from STARTMAP gets you to MAP. These elements are ordered\n\
- so that the KEYS increase in length. The first element is ([] . STARTMAP).\n\
- An optional argument PREFIX, if non-nil, should be a key sequence;\n\
- then the value includes only maps for prefixes that start with PREFIX.")
- (startmap, prefix)
- Lisp_Object startmap, prefix;
- {
- /* This function can GC */
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
- Lisp_Object accessible_keymaps = Qnil;
- struct accessible_keymaps_closure c;
- c.tail = Qnil;
- GCPRO4 (accessible_keymaps, c.tail, prefix, startmap);
-
- retry:
- startmap = get_keymap (startmap, 1, 1);
- if (NILP (prefix))
- prefix = make_vector (0, Qnil);
- else if (!VECTORP (prefix) || STRINGP (prefix))
- {
- prefix = wrong_type_argument (Qarrayp, prefix);
- goto retry;
- }
- else
- {
- int len = XINT (Flength (prefix));
- Lisp_Object def = Flookup_key (startmap, prefix, Qnil);
- Lisp_Object p;
- int iii;
- struct gcpro gcpro1;
-
- def = get_keymap (def, 0, 1);
- if (!KEYMAPP (def))
- goto RETURN;
-
- startmap = def;
- p = make_vector (len, Qnil);
- GCPRO1 (p);
- for (iii = 0; iii < len; iii++)
- {
- struct key_data key;
- define_key_parser (Faref (prefix, make_number (iii)), &key);
- vector_data (XVECTOR (p))[iii] = make_key_description (&key, 1);
- }
- UNGCPRO;
- prefix = p;
- }
-
- accessible_keymaps = list1 (Fcons (prefix, startmap));
-
- /* For each map in the list maps,
- look at any other maps it points to
- and stick them at the end if they are not already in the list */
-
- for (c.tail = accessible_keymaps;
- !NILP (c.tail);
- c.tail = XCDR (c.tail))
- {
- Lisp_Object thismap = Fcdr (Fcar (c.tail));
- CHECK_KEYMAP (thismap, 0);
- traverse_keymaps (thismap, Qnil,
- accessible_keymaps_keymap_mapper, &c);
- }
- RETURN:
- UNGCPRO;
- return (accessible_keymaps);
- }
-
-
-
- /************************************************************************/
- /* Pretty descriptions of key sequences */
- /************************************************************************/
-
- DEFUN ("key-description", Fkey_description, Skey_description, 1, 1, 0,
- "Return a pretty description of key-sequence KEYS.\n\
- Control characters turn into \"C-foo\" sequences, meta into \"M-foo\"\n\
- spaces are put between sequence elements, etc.")
- (keys)
- Lisp_Object keys;
- {
- if (INTP (keys) || CONSP (keys) || SYMBOLP (keys) || EVENTP (keys))
- {
- return Fsingle_key_description (keys);
- }
- else if (VECTORP (keys) ||
- STRINGP (keys))
- {
- Lisp_Object string = Qnil;
- /* Lisp_Object sep = Qnil; */
- int size = XINT (Flength (keys));
- int i;
-
- for (i = 0; i < size; i++)
- {
- Lisp_Object s2 = Fsingle_key_description
- (((STRINGP (keys))
- ? make_number ((unsigned char) string_char (XSTRING (keys), i))
- : vector_data (XVECTOR (keys))[i]));
-
- if (i == 0)
- string = s2;
- else
- {
- /* if (NILP (sep)) Lisp_Object sep = build_string (" ") */;
- string = concat2 (string, concat2 (Vsingle_space_string, s2));
- }
- }
- return (string);
- }
- return Fkey_description (wrong_type_argument (Qsequencep, keys));
- }
-
- DEFUN ("single-key-description", Fsingle_key_description,
- Ssingle_key_description, 1, 1, 0,
- "Return a pretty description of command character KEY.\n\
- Control characters turn into C-whatever, etc.\n\
- This differs from `text-char-description' in that it returns a description\n\
- of a key read from the user rather than a character from a buffer.")
- (key)
- Lisp_Object key;
- {
- if (SYMBOLP (key))
- key = Fcons (key, Qnil); /* sleaze sleaze */
-
- if (EVENTP (key) || CHARP (key))
- {
- char buf [255];
- if (INTP (key))
- {
- struct Lisp_Event event;
- event.event_type = empty_event;
- character_to_event (XINT (key), &event, 0);
- format_event_object (buf, &event, 1);
- }
- else
- format_event_object (buf, XEVENT (key), 1);
- return (build_string (buf));
- }
-
- if (CONSP (key))
- {
- char buf [255];
- char *bufp = buf;
- Lisp_Object rest;
- buf[0]=0;
- LIST_LOOP (rest, key)
- {
- Lisp_Object keysym = XCAR (rest);
- if (EQ (keysym, Qcontrol)) strcpy (bufp, "C-"), bufp += 2;
- else if (EQ (keysym, Qctrl)) strcpy (bufp, "C-"), bufp += 2;
- else if (EQ (keysym, Qmeta)) strcpy (bufp, "M-"), bufp += 2;
- else if (EQ (keysym, Qsuper)) strcpy (bufp, "S-"), bufp += 2;
- else if (EQ (keysym, Qhyper)) strcpy (bufp, "H-"), bufp += 2;
- else if (EQ (keysym, Qalt)) strcpy (bufp, "A-"), bufp += 2;
- else if (EQ (keysym, Qshift)) strcpy (bufp, "Sh-"), bufp += 3;
- else if (INTP (keysym))
- *bufp = XINT (keysym), bufp++, *bufp = 0;
- else
- {
- CHECK_SYMBOL (keysym, 0);
- #if 0 /* This is bogus */
- if (EQ (keysym, QKlinefeed)) strcpy (bufp, "LFD");
- else if (EQ (keysym, QKtab)) strcpy (bufp, "TAB");
- else if (EQ (keysym, QKreturn)) strcpy (bufp, "RET");
- else if (EQ (keysym, QKescape)) strcpy (bufp, "ESC");
- else if (EQ (keysym, QKdelete)) strcpy (bufp, "DEL");
- else if (EQ (keysym, QKspace)) strcpy (bufp, "SPC");
- else if (EQ (keysym, QKbackspace)) strcpy (bufp, "BS");
- else
- #endif
- strcpy (bufp, (char *) string_data (XSYMBOL (keysym)->name));
- if (!NILP (XCDR (rest)))
- signal_simple_error ("invalid key description",
- key);
- }
- }
- return build_string (buf);
- }
- return Fsingle_key_description
- (wrong_type_argument (intern ("char-or-event-p"), key));
- }
-
- DEFUN ("text-char-description", Ftext_char_description, Stext_char_description,
- 1, 1, 0,
- "Return a pretty description of file-character CHAR.\n\
- Unprintable characters turn into \"^char\" or \\NNN, depending on the value\n\
- of the `ctl-arrow' variable.\n\
- This differs from `single-key-description' in that it returns a description\n\
- of a character from a buffer rather than a key read from the user.")
- (chr)
- Lisp_Object chr;
- {
- Bufbyte buf[200];
- Bufbyte *p;
- unsigned int c;
- Lisp_Object ctl_arrow = current_buffer->ctl_arrow;
- int ctl_p = !NILP (ctl_arrow);
- int printable_min = (INTP (ctl_arrow)
- ? XINT (ctl_arrow)
- : ((EQ (ctl_arrow, Qt) || EQ (ctl_arrow, Qnil))
- ? 256 : 160));
-
- if (EVENTP (chr))
- {
- Lisp_Object ch = Fevent_to_character (chr, Qnil, Qnil, Qt);
- if (NILP (ch))
- return
- signal_simple_continuable_error
- ("character has no ASCII equivalent", Fcopy_event (chr, Qnil));
- chr = ch;
- }
-
- CHECK_COERCE_CHAR (chr, 0);
-
- c = XINT (chr);
- p = buf;
-
- if (c >= printable_min)
- {
- p += emchar_to_charptr (c, p);
- }
- else if (c < 040 && ctl_p)
- {
- *p++ = '^';
- *p++ = c + 64; /* 'A' - 1 */
- }
- else if (c == 0177)
- {
- *p++ = '^';
- *p++ = '?';
- }
- else if (c >= 0200 || c < 040)
- {
- *p++ = '\\';
- #ifdef MULE
- /* !!#### This syntax is not readable. It will
- be interpreted as a 3-digit octal number rather
- than a 7-digit octal number. */
- if (c >= 0400)
- {
- *p++ = '0' + ((c & 07000000) >> 18);
- *p++ = '0' + ((c & 0700000) >> 15);
- *p++ = '0' + ((c & 070000) >> 12);
- *p++ = '0' + ((c & 07000) >> 9);
- }
- #endif
- *p++ = '0' + ((c & 0700) >> 6);
- *p++ = '0' + ((c & 0070) >> 3);
- *p++ = '0' + ((c & 0007));
- }
- else
- {
- p += emchar_to_charptr (c, p);
- }
-
- *p = 0;
- return build_string ((char *) buf);
- }
-
-
- /************************************************************************/
- /* where-is (mapping bindings to keys) */
- /************************************************************************/
-
- static Lisp_Object
- where_is_internal (Lisp_Object definition, Lisp_Object *maps, int nmaps,
- Lisp_Object firstonly, char *target_buffer);
-
- DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 5, 0,
- "Return list of keys that invoke DEFINITION in KEYMAPS.\n\
- KEYMAPS can be either a keymap (meaning search in that keymap and the\n\
- current global keymap) or a list of keymaps (meaning search in exactly\n\
- those keymaps and no others). If KEYMAPS is nil, search in the currently\n\
- applicable maps for EVENT-OR-KEYS (this is equivalent to specifying\n\
- `(current-keymaps EVENT-OR-KEYS)' as the argument to KEYMAPS).\n\
- \n\
- If optional 3rd arg FIRSTONLY is non-nil, return a vector representing\n\
- the first key sequence found, rather than a list of all possible key\n\
- sequences.\n\
- \n\
- If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\
- to other keymaps or slots. This makes it possible to search for an\n\
- indirect definition itself.")
- (definition, keymaps, firstonly, noindirect, event_or_keys)
- Lisp_Object definition, keymaps, firstonly, noindirect, event_or_keys;
- {
- /* This function can GC */
- Lisp_Object maps[100];
- Lisp_Object *gubbish = maps;
- int nmaps;
-
- /* Get keymaps as an array */
- if (NILP (keymaps))
- {
- nmaps = get_relevant_keymaps (event_or_keys, countof (maps),
- gubbish);
- if (nmaps > countof (maps))
- {
- gubbish = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- nmaps = get_relevant_keymaps (event_or_keys, nmaps, gubbish);
- }
- }
- else if (CONSP (keymaps))
- {
- Lisp_Object rest;
- int i;
-
- nmaps = XINT (Flength (keymaps));
- if (nmaps > countof (maps))
- {
- gubbish = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- }
- for (rest = keymaps, i = 0; !NILP (rest);
- rest = XCDR (keymaps), i++)
- {
- gubbish[i] = get_keymap (XCAR (keymaps), 1, 1);
- }
- }
- else
- {
- nmaps = 1;
- gubbish[0] = get_keymap (keymaps, 1, 1);
- if (!EQ (gubbish[0], Vcurrent_global_map))
- {
- gubbish[1] = Vcurrent_global_map;
- nmaps++;
- }
- }
-
- return where_is_internal (definition, gubbish, nmaps, firstonly, 0);
- }
-
- /* This function is like
- (key-description (where-is-internal definition nil t))
- except that it writes its output into a (char *) buffer that you
- provide; it doesn't cons (or allocate memory) at all, so it's
- very fast. This is used by menubar.c.
- */
- void
- where_is_to_char (Lisp_Object definition, char *buffer)
- {
- /* This function can GC */
- Lisp_Object maps[100];
- Lisp_Object *gubbish = maps;
- int nmaps;
-
- /* Get keymaps as an array */
- nmaps = get_relevant_keymaps (Qnil, countof (maps), gubbish);
- if (nmaps > countof (maps))
- {
- gubbish = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- nmaps = get_relevant_keymaps (Qnil, nmaps, gubbish);
- }
-
- buffer[0] = 0;
- where_is_internal (definition, maps, nmaps, Qt, buffer);
- }
-
-
- static Lisp_Object
- raw_keys_to_keys (struct key_data *keys, int count)
- {
- Lisp_Object result = make_vector (count, Qnil);
- while (count--)
- vector_data (XVECTOR (result)) [count] =
- make_key_description (&(keys[count]), 1);
- return (result);
- }
-
-
- static void
- format_raw_keys (struct key_data *keys, int count, char *buf)
- {
- int i;
- struct Lisp_Event event;
- event.event_type = key_press_event;
- for (i = 0; i < count; i++)
- {
- event.event.key.keysym = keys[i].keysym;
- event.event.key.modifiers = keys[i].modifiers;
- format_event_object (buf, &event, 1);
- buf += strlen (buf);
- if (i < count-1)
- buf[0] = ' ', buf++;
- }
- }
-
-
- /* definition is the thing to look for.
- map is a keymap.
- shadow is an array of shadow_count keymaps; if there is a different
- binding in any of the keymaps of a key that we are considering
- returning, then we reconsider.
- firstonly means give up after finding the first match;
- keys_so_far and modifiers_so_far describe which map we're looking in;
- If we're in the "meta" submap of the map that "C-x 4" is bound to,
- then keys_so_far will be {(control x), \4}, and modifiers_so_far
- will be MOD_META. That is, keys_so_far is the chain of keys that we
- have followed, and modifiers_so_far_so_far is the bits (partial keys)
- beyond that.
-
- (keys_so_far is a global buffer and the keys_count arg says how much
- of it we're currently interested in.)
-
- If target_buffer is provided, then we write a key-description into it,
- to avoid consing a string. This only works with firstonly on.
- */
-
- struct where_is_closure
- {
- Lisp_Object definition;
- Lisp_Object *shadow;
- int shadow_count;
- int firstonly;
- int keys_count;
- unsigned int modifiers_so_far;
- char *target_buffer;
- struct key_data *keys_so_far;
- int keys_so_far_total_size;
- int keys_so_far_malloced;
- };
-
- static Lisp_Object where_is_recursive_mapper (Lisp_Object map, void *arg);
-
- static Lisp_Object
- where_is_recursive_mapper (Lisp_Object map, void *arg)
- {
- /* This function can GC */
- struct where_is_closure *c = arg;
- Lisp_Object definition = c->definition;
- CONST int firstonly = c->firstonly;
- CONST unsigned int keys_count = c->keys_count;
- CONST unsigned int modifiers_so_far = c->modifiers_so_far;
- char *target_buffer = c->target_buffer;
- Lisp_Object keys = Fgethash (definition,
- XKEYMAP (map)->inverse_table,
- Qnil);
- Lisp_Object submaps;
- Lisp_Object result = Qnil;
-
- if (!NILP (keys))
- {
- /* One or more keys in this map match the definition we're looking
- for. Verify that these bindings aren't shadowed by other bindings
- in the shadow maps. Either nil or number as value from
- raw_lookup_key() means undefined.
- */
- struct key_data *so_far = c->keys_so_far;
-
- for (;;) /* loop over all keys that match */
- {
- Lisp_Object k = ((CONSP (keys)) ? XCAR (keys) : keys);
- int i;
-
- so_far [keys_count].keysym = k;
- so_far [keys_count].modifiers = modifiers_so_far;
-
- /* now loop over all shadow maps */
- for (i = 0; i < c->shadow_count; i++)
- {
- Lisp_Object shadowed = raw_lookup_key (c->shadow[i],
- so_far,
- keys_count + 1,
- 0, 1);
-
- if (NILP (shadowed) || INTP (shadowed) ||
- EQ (shadowed, definition))
- continue; /* we passed this test; it's not shadowed here. */
- else
- /* ignore this key binding, since it actually has a
- different binding in a shadowing map */
- goto c_doesnt_have_proper_loop_exit_statements;
- }
-
- /* OK, the key is for real */
- if (target_buffer)
- {
- if (!firstonly) abort ();
- format_raw_keys (so_far, keys_count + 1, target_buffer);
- return (make_number (1));
- }
- else if (firstonly)
- return raw_keys_to_keys (so_far, keys_count + 1);
- else
- result = Fcons (raw_keys_to_keys (so_far, keys_count + 1),
- result);
-
- c_doesnt_have_proper_loop_exit_statements:
- /* now on to the next matching key ... */
- if (!CONSP (keys)) break;
- keys = XCDR (keys);
- }
- }
-
- /* Now search the sub-keymaps of this map.
- If we're in "firstonly" mode and have already found one, this
- point is not reached. If we get one from lower down, either
- return it immediately (in firstonly mode) or tack it onto the
- end of the ones we've gotten so far.
- */
- for (submaps = keymap_submaps (map);
- !NILP (submaps);
- submaps = XCDR (submaps))
- {
- Lisp_Object key = XCAR (XCAR (submaps));
- Lisp_Object submap = XCDR (XCAR (submaps));
- unsigned int lower_modifiers;
- int lower_keys_count = keys_count;
- unsigned int bucky;
-
- submap = get_keymap (submap, 0, 1);
-
- if (EQ (submap, map))
- /* Arrgh! Some loser has introduced a loop... */
- continue;
-
- /* If this is not a keymap, then that's probably because someone
- did an `fset' of a symbol that used to point to a map such that
- it no longer does. Sigh. Ignore this, and invalidate the cache
- so that it doesn't happen to us next time too.
- */
- if (NILP (submap))
- {
- XKEYMAP (map)->sub_maps_cache = Qt;
- continue;
- }
-
- /* If the map is a "bucky" map, then add a bit to the
- modifiers_so_far list.
- Otherwise, add a new raw_key onto the end of keys_so_far.
- */
- bucky = MODIFIER_HASH_KEY_P (key);
- if (bucky != 0)
- lower_modifiers = (modifiers_so_far | bucky);
- else
- {
- struct key_data *so_far = c->keys_so_far;
- lower_modifiers = 0;
- so_far [lower_keys_count].keysym = key;
- so_far [lower_keys_count].modifiers = modifiers_so_far;
- lower_keys_count++;
- }
-
- if (lower_keys_count >= c->keys_so_far_total_size)
- {
- int size = lower_keys_count + 50;
- if (! c->keys_so_far_malloced)
- {
- struct key_data *new = xmalloc (size * sizeof (struct key_data));
- memcpy ((void *)new, (const void *)c->keys_so_far,
- c->keys_so_far_total_size * sizeof (struct key_data));
- }
- else
- c->keys_so_far = xrealloc (c->keys_so_far,
- size * sizeof (struct key_data));
-
- c->keys_so_far_total_size = size;
- c->keys_so_far_malloced = 1;
- }
-
- {
- Lisp_Object lower;
-
- c->keys_count = lower_keys_count;
- c->modifiers_so_far = lower_modifiers;
-
- lower = traverse_keymaps (submap, Qnil, where_is_recursive_mapper,
- c);
- c->keys_count = keys_count;
- c->modifiers_so_far = modifiers_so_far;
-
- if (!firstonly)
- result = nconc2 (lower, result);
- else if (!NILP (lower))
- return (lower);
- }
- }
- return (result);
- }
-
-
- static Lisp_Object
- where_is_internal (Lisp_Object definition, Lisp_Object *maps, int nmaps,
- Lisp_Object firstonly, char *target_buffer)
- {
- /* This function can GC */
- Lisp_Object result = Qnil;
- int i;
- struct key_data raw[20];
- struct where_is_closure c;
-
- c.definition = definition;
- c.shadow = maps;
- c.firstonly = !NILP (firstonly);
- c.target_buffer = target_buffer;
- c.keys_so_far = raw;
- c.keys_so_far_total_size = countof (raw);
- c.keys_so_far_malloced = 0;
-
- /* Loop over each of the maps, accumulating the keys found.
- For each map searched, all previous maps shadow this one
- so that bogus keys aren't listed. */
- for (i = 0; i < nmaps; i++)
- {
- Lisp_Object this_result;
- c.shadow_count = i;
- /* Reset the things set in each iteration */
- c.keys_count = 0;
- c.modifiers_so_far = 0;
-
- this_result = traverse_keymaps (maps[i], Qnil, where_is_recursive_mapper,
- &c);
- if (!NILP (firstonly))
- {
- result = this_result;
- if (!NILP (result))
- break;
- }
- else
- result = nconc2 (this_result, result);
- }
-
- if (NILP (firstonly))
- result = Fnreverse (result);
-
- if (c.keys_so_far_malloced)
- xfree (c.keys_so_far);
- return (result);
- }
-
-
- /************************************************************************/
- /* Describing keymaps */
- /************************************************************************/
-
- DEFUN ("describe-bindings-internal",
- Fdescribe_bindings_internal, Sdescribe_bindings_internal, 1, 5, 0,
- "Insert a list of all defined keys and their definitions in MAP.\n\
- Optional second argument ALL says whether to include even \"uninteresting\"\n\
- definitions (ie symbols with a non-nil `suppress-keymap' property.\n\
- Third argument SHADOW is a list of keymaps whose bindings shadow those\n\
- of map; if a binding is present in any shadowing map, it is not printed.\n\
- Fourth argument PREFIX, if non-nil, should be a key sequence;\n\
- only bindings which start with that key sequence will be printed.\n\
- Fifth argument MOUSE-ONLY-P says to only print bindings for mouse clicks.")
- (map, all, shadow, prefix, mouse_only_p)
- Lisp_Object map, all, shadow, prefix, mouse_only_p;
- {
- /* This function can GC */
- describe_map_tree (map, NILP (all), shadow, prefix,
- !NILP (mouse_only_p));
- return (Qnil);
- }
-
-
- /* Insert a desription of the key bindings in STARTMAP,
- followed by those of all maps reachable through STARTMAP.
- If PARTIAL is nonzero, omit certain "uninteresting" commands
- (such as `undefined').
- If SHADOW is non-nil, it is a list of other maps;
- don't mention keys which would be shadowed by any of them
- If PREFIX is non-nil, only list bindings which start with those keys
- */
-
- void
- describe_map_tree (Lisp_Object startmap, int partial, Lisp_Object shadow,
- Lisp_Object prefix, int mice_only_p)
- {
- /* This function can GC */
- Lisp_Object maps = Qnil;
- struct gcpro gcpro1, gcpro2; /* get_keymap may autoload */
- GCPRO2 (maps, shadow);
-
- maps = Faccessible_keymaps (startmap, prefix);
-
- for (; !NILP (maps); maps = Fcdr (maps))
- {
- Lisp_Object sub_shadow = Qnil;
- Lisp_Object elt = Fcar (maps);
- Lisp_Object tail = shadow;
- int no_prefix = (VECTORP (Fcar (elt))
- && XINT (Flength (Fcar (elt))) == 0);
- struct gcpro gcpro1, gcpro2, gcpro3;
- GCPRO3 (sub_shadow, elt, tail);
-
- for (; CONSP (tail); tail = XCDR (tail))
- {
- Lisp_Object sh = XCAR (tail);
-
- /* If the sequence by which we reach this keymap is zero-length,
- then the shadow maps for this keymap are just SHADOW. */
- if (no_prefix)
- ;
- /* If the sequence by which we reach this keymap actually has
- some elements, then the sequence's definition in SHADOW is
- what we should use. */
- else
- {
- sh = Flookup_key (sh, Fcar (elt), Qt);
- if (INTP (sh))
- sh = Qnil;
- }
-
- if (!NILP (sh))
- {
- Lisp_Object shm = get_keymap (sh, 0, 1);
- if (!KEYMAPP (shm))
- /* If sh is not nil and not a keymap, it completely shadows
- this map, so don't describe this map at all. */
- goto SKIP;
- sub_shadow = Fcons (shm, sub_shadow);
- }
- }
-
- {
- /* Describe the contents of map MAP, assuming that this map
- itself is reached by the sequence of prefix keys KEYS (a vector).
- PARTIAL and SHADOW are as in `describe_map_tree'. */
- Lisp_Object keysdesc
- = ((!no_prefix)
- ? concat2 (Fkey_description (Fcar (elt)), Vsingle_space_string)
- : Qnil);
- describe_map (Fcdr (elt), keysdesc,
- describe_command,
- partial,
- sub_shadow,
- mice_only_p);
- }
- SKIP:
- ;
- }
- UNGCPRO;
- }
-
-
- static void
- describe_command (Lisp_Object definition)
- {
- /* This function can GC */
- Lisp_Object buffer;
- int keymapp = !NILP (Fkeymapp (definition));
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (definition, buffer);
-
- XSETBUFFER (buffer, current_buffer);
- Findent_to (make_number (16), make_number (3), buffer);
- if (keymapp)
- buffer_insert_c_string (XBUFFER (buffer), "<< ");
-
- if (SYMBOLP (definition))
- {
- buffer_insert1 (XBUFFER (buffer), Fsymbol_name (definition));
- }
- else if (STRINGP (definition) || VECTORP (definition))
- {
- buffer_insert_c_string (XBUFFER (buffer), "Kbd Macro: ");
- buffer_insert1 (XBUFFER (buffer), Fkey_description (definition));
- }
- else if (BYTECODEP (definition))
- buffer_insert_c_string (XBUFFER (buffer), "Anonymous Compiled Function");
- else if (CONSP (definition) && EQ (XCAR (definition), Qlambda))
- buffer_insert_c_string (XBUFFER (buffer), "Anonymous Lambda");
- else if (KEYMAPP (definition))
- {
- Lisp_Object name = XKEYMAP (definition)->name;
- if (STRINGP (name) || (SYMBOLP (name) && !NILP (name)))
- {
- buffer_insert_c_string (XBUFFER (buffer), "Prefix command ");
- if (SYMBOLP (name)
- && EQ (find_symbol_value (name), definition))
- buffer_insert1 (XBUFFER (buffer), Fsymbol_name (name));
- else
- {
- buffer_insert1 (XBUFFER (buffer), Fprin1_to_string (name, Qnil));
- }
- }
- else
- buffer_insert_c_string (XBUFFER (buffer), "Prefix Command");
- }
- else
- buffer_insert_c_string (XBUFFER (buffer), "??");
-
- if (keymapp)
- buffer_insert_c_string (XBUFFER (buffer), " >>");
- buffer_insert_c_string (XBUFFER (buffer), "\n");
- UNGCPRO;
- }
-
- struct describe_map_closure
- {
- Lisp_Object *list; /* pointer to the list to update */
- Lisp_Object partial; /* whether to ignore suppressed commands */
- Lisp_Object shadow; /* list of maps shadowing this one */
- Lisp_Object self; /* this map */
- Lisp_Object self_root; /* this map, or some map that has this map as
- a parent. this is the base of the tree */
- int mice_only_p; /* whether we are to display only button bindings */
- };
-
- struct describe_map_shadow_closure
- {
- CONST struct key_data *raw_key;
- Lisp_Object self;
- };
-
- static Lisp_Object
- describe_map_mapper_shadow_search (Lisp_Object map, void *arg)
- {
- struct describe_map_shadow_closure *c = arg;
-
- if (EQ (map, c->self))
- return (Qzero); /* Not shadowed; terminate search */
- else if (!NILP (keymap_lookup_directly (map,
- c->raw_key->keysym,
- c->raw_key->modifiers)))
- return (Qt);
- else
- return (Qnil);
- }
-
-
- static Lisp_Object
- keymap_lookup_inherited_mapper (Lisp_Object km, void *arg)
- {
- struct key_data *k = arg;
- return (keymap_lookup_directly (km, k->keysym, k->modifiers));
- }
-
-
- static void
- describe_map_mapper (CONST struct key_data *key,
- Lisp_Object binding,
- void *describe_map_closure)
- {
- /* This function can GC */
- struct describe_map_closure *closure = describe_map_closure;
- Lisp_Object keysym = key->keysym;
- unsigned int modifiers = key->modifiers;
-
- /* Dont mention suppressed commands. */
- if (SYMBOLP (binding)
- && !NILP (closure->partial)
- && !NILP (Fget (binding, closure->partial, Qnil)))
- return;
-
- /* If we're only supposed to display mouse bindings and this isn't one,
- then bug out. */
- if (closure->mice_only_p &&
- (! (EQ (keysym, Qbutton0) || EQ (keysym, Qbutton1)
- || EQ (keysym, Qbutton2) || EQ (keysym, Qbutton3)
- || EQ (keysym, Qbutton4) || EQ (keysym, Qbutton5)
- || EQ (keysym, Qbutton6) || EQ (keysym, Qbutton7))))
- return;
-
- /* If this command in this map is shadowed by some other map, ignore it. */
- {
- Lisp_Object tail;
-
- for (tail = closure->shadow; CONSP (tail); tail = XCDR (tail))
- {
- QUIT;
- if (!NILP (traverse_keymaps (XCAR (tail), Qnil,
- keymap_lookup_inherited_mapper,
- /* Cast to discard `const' */
- (void *)key)))
- return;
- }
- }
-
- /* If this key is in some map of which this map is a parent, then ignore
- it (in that case, it has been shadowed).
- */
- {
- Lisp_Object sh;
- struct describe_map_shadow_closure c;
- c.raw_key = key;
- c.self = closure->self;
-
- sh = traverse_keymaps (closure->self_root, Qnil,
- describe_map_mapper_shadow_search, &c);
- if (!NILP (sh) && !EQ (sh, Qzero))
- return;
- }
-
- /* Otherwise add it to the list to be sorted. */
- *(closure->list) = Fcons (Fcons (Fcons (keysym, make_number (modifiers)),
- binding),
- *(closure->list));
- }
-
-
- static int
- describe_map_sort_predicate (Lisp_Object obj1, Lisp_Object obj2,
- Lisp_Object pred)
- {
- /* obj1 and obj2 are conses of the form
- ( ( <keysym> . <modifiers> ) . <binding> )
- keysym and modifiers are used, binding is ignored.
- */
- unsigned int bit1, bit2;
- obj1 = XCAR (obj1);
- obj2 = XCAR (obj2);
- bit1 = XINT (XCDR (obj1));
- bit2 = XINT (XCDR (obj2));
- if (bit1 != bit2)
- return ((bit1 < bit2) ? 1 : -1);
- else
- return map_keymap_sort_predicate (obj1, obj2, pred);
- }
-
- /* Elide 2 or more consecutive numeric keysyms bound to the same thing,
- or 2 or more symbolic keysyms that are bound to the same thing and
- have consecutive character-set-properties.
- */
- static int
- elide_next_two_p (Lisp_Object list)
- {
- Lisp_Object s1, s2;
-
- if (NILP (XCDR (list)))
- return 0;
-
- /* next two bindings differ */
- if (!EQ (XCDR (XCAR (list)),
- XCDR (XCAR (XCDR (list)))))
- return 0;
-
- /* next two modifier-sets differ */
- if (!EQ (XCDR (XCAR (XCAR (list))),
- XCDR (XCAR (XCAR (XCDR (list))))))
- return 0;
-
- s1 = XCAR (XCAR (XCAR (list)));
- s2 = XCAR (XCAR (XCAR (XCDR (list))));
-
- if (SYMBOLP (s1))
- {
- Lisp_Object code = Fget (s1, Vcharacter_set_property, Qnil);
- if (INTP (code)) s1 = code;
- else return 0;
- }
- if (SYMBOLP (s2))
- {
- Lisp_Object code = Fget (s2, Vcharacter_set_property, Qnil);
- if (INTP (code)) s2 = code;
- else return 0;
- }
-
- if (XINT (s1) == XINT (s2) ||
- XINT (s1) + 1 == XINT (s2))
- return 1;
- return 0;
- }
-
-
- static Lisp_Object
- describe_map_parent_mapper (Lisp_Object keymap, void *arg)
- {
- /* This function can GC */
- struct describe_map_closure *describe_map_closure = arg;
- describe_map_closure->self = keymap;
- map_keymap (XKEYMAP (keymap)->table,
- 0, /* don't sort: we'll do it later */
- describe_map_mapper, describe_map_closure);
- return (Qnil);
- }
-
-
- static void
- describe_map (Lisp_Object keymap, Lisp_Object elt_prefix,
- void (*elt_describer) (Lisp_Object),
- int partial,
- Lisp_Object shadow,
- int mice_only_p)
- {
- /* This function can GC */
- struct describe_map_closure describe_map_closure;
- Lisp_Object list = Qnil;
- struct buffer *buf = current_buffer;
- int printable_min = (INTP (buf->ctl_arrow)
- ? XINT (buf->ctl_arrow)
- : ((EQ (buf->ctl_arrow, Qt)
- || EQ (buf->ctl_arrow, Qnil))
- ? 256 : 160));
- int elided = 0;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-
- keymap = get_keymap (keymap, 1, 1);
- describe_map_closure.partial = (partial ? Qsuppress_keymap : Qnil);
- describe_map_closure.shadow = shadow;
- describe_map_closure.list = &list;
- describe_map_closure.self_root = keymap;
- describe_map_closure.mice_only_p = mice_only_p;
-
- GCPRO4 (keymap, elt_prefix, shadow, list);
-
- traverse_keymaps (keymap, Qnil,
- describe_map_parent_mapper, &describe_map_closure);
-
- if (!NILP (list))
- {
- list = list_sort (list, Qnil, describe_map_sort_predicate);
- buffer_insert_c_string (buf, "\n");
- while (!NILP (list))
- {
- Lisp_Object elt = XCAR (XCAR (list));
- Lisp_Object keysym = XCAR (elt);
- unsigned int modifiers = XINT (XCDR (elt));
-
- if (!NILP (elt_prefix))
- buffer_insert_lisp_string (buf, elt_prefix);
-
- if (modifiers & MOD_META) buffer_insert_c_string (buf, "M-");
- if (modifiers & MOD_CONTROL) buffer_insert_c_string (buf, "C-");
- if (modifiers & MOD_SUPER) buffer_insert_c_string (buf, "S-");
- if (modifiers & MOD_HYPER) buffer_insert_c_string (buf, "H-");
- if (modifiers & MOD_ALT) buffer_insert_c_string (buf, "Alt-");
- if (modifiers & MOD_SHIFT) buffer_insert_c_string (buf, "Sh-");
- if (SYMBOLP (keysym))
- {
- Lisp_Object code = Fget (keysym, Vcharacter_set_property, Qnil);
- Emchar c = (INTP (code) ? XINT (code) : -1);
- /* Calling Fsingle_key_description() would cons more */
- #if 0 /* This is bogus */
- if (EQ (keysym, QKlinefeed))
- buffer_insert_c_string (buf, "LFD");
- else if (EQ (keysym, QKtab))
- buffer_insert_c_string (buf, "TAB");
- else if (EQ (keysym, QKreturn))
- buffer_insert_c_string (buf, "RET");
- else if (EQ (keysym, QKescape))
- buffer_insert_c_string (buf, "ESC");
- else if (EQ (keysym, QKdelete))
- buffer_insert_c_string (buf, "DEL");
- else if (EQ (keysym, QKspace))
- buffer_insert_c_string (buf, "SPC");
- else if (EQ (keysym, QKbackspace))
- buffer_insert_c_string (buf, "BS");
- else
- #endif
- if (c >= printable_min) buffer_insert_emacs_char (buf, c);
- else buffer_insert1 (buf, Fsymbol_name (keysym));
- }
- else if (INTP (keysym))
- buffer_insert_emacs_char (buf, XINT (keysym));
- else
- buffer_insert_c_string (buf, "---bad keysym---");
-
- if (elided)
- elided = 0;
- else
- {
- int k = 0;
-
- while (elide_next_two_p (list))
- {
- k++;
- list = XCDR (list);
- }
- if (k != 0)
- {
- if (k == 1)
- buffer_insert_c_string (buf, ", ");
- else
- buffer_insert_c_string (buf, " .. ");
- elided = 1;
- continue;
- }
- }
-
- /* Print a description of the definition of this character. */
- (*elt_describer) (XCDR (XCAR (list)));
- list = XCDR (list);
- }
- }
- UNGCPRO;
- }
-
-
- void
- syms_of_keymap (void)
- {
- defsymbol (&Qminor_mode_map_alist, "minor-mode-map-alist");
-
- defsymbol (&Qkeymap, "keymap");
- defsymbol (&Qkeymapp, "keymapp");
-
- defsymbol (&Qsuppress_keymap, "suppress-keymap");
-
- defsymbol (&Qmodeline_map, "modeline-map");
- defsymbol (&Qtoolbar_map, "toolbar-map");
-
- defsubr (&Skeymap_parents);
- defsubr (&Sset_keymap_parents);
- /*defsubr (&Skeymap_name); */
- defsubr (&Sset_keymap_name);
- defsubr (&Skeymap_prompt);
- defsubr (&Sset_keymap_prompt);
- defsubr (&Skeymap_default_binding);
- defsubr (&Sset_keymap_default_binding);
-
- defsubr (&Skeymapp);
- defsubr (&Smake_keymap);
- defsubr (&Smake_sparse_keymap);
-
- defsubr (&Scopy_keymap);
- defsubr (&Skeymap_fullness);
- defsubr (&Smap_keymap);
- defsubr (&Sevent_matches_key_specifier_p);
- defsubr (&Sdefine_key);
- defsubr (&Slookup_key);
- defsubr (&Skey_binding);
- defsubr (&Suse_global_map);
- defsubr (&Suse_local_map);
- defsubr (&Scurrent_local_map);
- defsubr (&Scurrent_global_map);
- defsubr (&Scurrent_keymaps);
- defsubr (&Saccessible_keymaps);
- defsubr (&Skey_description);
- defsubr (&Ssingle_key_description);
- defsubr (&Swhere_is_internal);
- defsubr (&Sdescribe_bindings_internal);
-
- defsubr (&Stext_char_description);
-
- defsymbol (&Qcontrol, "control");
- defsymbol (&Qctrl, "ctrl");
- defsymbol (&Qmeta, "meta");
- defsymbol (&Qsuper, "super");
- defsymbol (&Qhyper, "hyper");
- defsymbol (&Qalt, "alt");
- defsymbol (&Qshift, "shift");
- defsymbol (&Qbutton0, "button0");
- defsymbol (&Qbutton1, "button1");
- defsymbol (&Qbutton2, "button2");
- defsymbol (&Qbutton3, "button3");
- defsymbol (&Qbutton4, "button4");
- defsymbol (&Qbutton5, "button5");
- defsymbol (&Qbutton6, "button6");
- defsymbol (&Qbutton7, "button7");
- defsymbol (&Qbutton0up, "button0up");
- defsymbol (&Qbutton1up, "button1up");
- defsymbol (&Qbutton2up, "button2up");
- defsymbol (&Qbutton3up, "button3up");
- defsymbol (&Qbutton4up, "button4up");
- defsymbol (&Qbutton5up, "button5up");
- defsymbol (&Qbutton6up, "button6up");
- defsymbol (&Qbutton7up, "button7up");
- defsymbol (&Qmenu_selection, "menu-selection");
- defsymbol (&QLFD, "LFD");
- defsymbol (&QTAB, "TAB");
- defsymbol (&QRET, "RET");
- defsymbol (&QESC, "ESC");
- defsymbol (&QDEL, "DEL");
- defsymbol (&QBS, "BS");
- }
-
- void
- vars_of_keymap (void)
- {
- DEFVAR_LISP ("meta-prefix-char", &Vmeta_prefix_char,
- "Meta-prefix character.\n\
- This character followed by some character `foo' turns into `Meta-foo'.\n\
- This can be any form recognized as a single key specifier.\n\
- To disable the meta-prefix-char, set it to a negative number.");
- Vmeta_prefix_char = make_number (033);
-
- DEFVAR_LISP ("mouse-grabbed-buffer", &Vmouse_grabbed_buffer,
- "A buffer which should be consulted first for all mouse activity.\n\
- When a mouse-clicked it processed, it will first be looked up in the\n\
- local-map of this buffer, and then through the normal mechanism if there\n\
- is no binding for that click. This buffer's value of `mode-motion-hook'\n\
- will be consulted instead of the `mode-motion-hook' of the buffer of the\n\
- window under the mouse. You should *bind* this, not set it.");
- Vmouse_grabbed_buffer = Qnil;
-
- /* defsymbol (&Qoverriding_local_map, "overriding-local-map"); */
- DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
- "Keymap that overrides all other local keymaps.\n\
- If this variable is non-nil, it is used as a keymap instead of the\n\
- buffer's local map, and the minor mode keymaps and extent-local keymaps.\n\
- You should *bind* this, not set it.");
- Voverriding_local_map = Qnil;
-
- Fset (Qminor_mode_map_alist, Qnil);
-
- DEFVAR_INT ("keymap-tick", &keymap_tick,
- "Incremented for each change to any keymap.");
- keymap_tick = 0;
-
- staticpro (&Vcurrent_global_map);
-
- Vsingle_space_string = make_pure_string ((Bufbyte *) " ", 1, 1);
- staticpro (&Vsingle_space_string);
- }
-
- void
- complex_vars_of_keymap (void)
- {
- /* This function can GC */
- Lisp_Object ESC_prefix = intern ("ESC-prefix");
- Lisp_Object meta_disgustitute;
-
- Vcurrent_global_map = Fmake_keymap ();
-
- meta_disgustitute = Fmake_keymap ();
- Ffset (ESC_prefix, meta_disgustitute);
- /* no need to protect meta_disgustitute, though */
- keymap_store_internal (MAKE_MODIFIER_HASH_KEY (MOD_META),
- XKEYMAP (Vcurrent_global_map),
- meta_disgustitute);
- XKEYMAP (Vcurrent_global_map)->sub_maps_cache = Qt;
- }
-