Function: lookup-key

lookup-key is a function defined in keymap.c.

Signature

(lookup-key KEYMAP KEY &optional ACCEPT-DEFAULT)

Documentation

Look up key sequence KEY in KEYMAP. Return the definition.

This is a legacy function; see keymap-lookup for the recommended function to use instead.

A value of nil means undefined. See doc of define-key for kinds of definitions.

A number as value means KEY is "too long"; that is, characters or symbols in it except for the last one fail to be a valid sequence of prefix characters in KEYMAP. The number is how many characters at the front of KEY it takes to reach a non-prefix key. KEYMAP can also be a list of keymaps.

Normally, lookup-key ignores bindings for t, which act as default bindings, used when nothing else in the keymap applies; this makes it usable as a general function for probing keymaps. However, if the third optional argument ACCEPT-DEFAULT is non-nil, lookup-key will recognize the default bindings, just as read-key-sequence does.

View in manual

Probably introduced at or before Emacs version 13.

Source Code

// Defined in /usr/src/emacs/src/keymap.c
{
  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
  if (!NILP (found) && !NUMBERP (found))
    return found;

  /* Menu definitions might use mixed case symbols (notably in old
     versions of `easy-menu-define'), or use " " instead of "-".
     The rest of this function is about accepting these variations for
     backwards-compatibility.  (Bug#50752) */

  /* Just skip everything below unless this is a menu item.  */
  if (!VECTORP (key) || !(ASIZE (key) > 0)
      || !EQ (AREF (key, 0), Qmenu_bar))
    return found;

  /* Initialize the unicode case table, if it wasn't already.  */
  if (NILP (unicode_case_table))
    {
      unicode_case_table = uniprop_table (Qlowercase);
      /* uni-lowercase.el might be unavailable during bootstrap.  */
      if (NILP (unicode_case_table))
	return found;
      staticpro (&unicode_case_table);
    }

  ptrdiff_t key_len = ASIZE (key);
  Lisp_Object new_key = make_vector (key_len, Qnil);

  /* Try both the Unicode case table, and the buffer local one.
     Otherwise, we will fail for e.g. the "Turkish" language
     environment where 'I' does not downcase to 'i'.  */
  Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()};
  for (int tbl_num = 0; tbl_num < 2; tbl_num++)
    {
      /* First, let's try converting all symbols like "Foo-Bar-Baz" to
	 "foo-bar-baz".  */
      for (int i = 0; i < key_len; i++)
	{
	  Lisp_Object item = AREF (key, i);
	  if (!SYMBOLP (item))
	    ASET (new_key, i, item);
	  else
	    {
	      Lisp_Object key_item = Fsymbol_name (item);
	      Lisp_Object new_item;
	      if (!STRING_MULTIBYTE (key_item))
		new_item = Fdowncase (key_item);
	      else
		{
		  USE_SAFE_ALLOCA;
		  ptrdiff_t size = SCHARS (key_item), n;
		  if (ckd_mul (&n, size, MAX_MULTIBYTE_LENGTH))
		    n = PTRDIFF_MAX;
		  unsigned char *dst = SAFE_ALLOCA (n);
		  unsigned char *p = dst;
		  ptrdiff_t j_char = 0, j_byte = 0;

		  while (j_char < size)
		    {
		      int ch = fetch_string_char_advance (key_item,
							  &j_char, &j_byte);
		      Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num],
							    ch);
		      if (!NILP (ch_conv))
			CHAR_STRING (XFIXNUM (ch_conv), p);
		      else
			CHAR_STRING (ch, p);
		      p = dst + j_byte;
		    }
		  new_item = make_multibyte_string ((char *) dst,
						    SCHARS (key_item),
						    SBYTES (key_item));
		  SAFE_FREE ();
		}
	      ASET (new_key, i, Fintern (new_item, Qnil));
	    }
	}

      /* Check for match.  */
      found = lookup_key_1 (keymap, new_key, accept_default);
      if (!NILP (found) && !NUMBERP (found))
	break;

      /* If we still don't have a match, let's convert any spaces in
	 our lowercased string into dashes, e.g. "foo bar baz" to
	 "foo-bar-baz".  */
      for (int i = 0; i < key_len; i++)
	{
	  if (!SYMBOLP (AREF (new_key, i)))
	    continue;

	  Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));

	  /* If there are no spaces in this symbol, just skip it.  */
	  if (!strstr (SSDATA (lc_key), " "))
	    continue;

	  USE_SAFE_ALLOCA;
	  ptrdiff_t size = SCHARS (lc_key), n;
	  if (ckd_mul (&n, size, MAX_MULTIBYTE_LENGTH))
	    n = PTRDIFF_MAX;
	  unsigned char *dst = SAFE_ALLOCA (n);

	  /* We can walk the string data byte by byte, because UTF-8
	     encoding ensures that no other byte of any multibyte
	     sequence will ever include a 7-bit byte equal to an ASCII
	     single-byte character.  */
	  memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
	  for (int i = 0; i < SBYTES (lc_key); ++i)
	    {
	      if (dst[i] == ' ')
		dst[i] = '-';
	    }
	  Lisp_Object new_it =
	    make_multibyte_string ((char *) dst,
				   SCHARS (lc_key), SBYTES (lc_key));
	  ASET (new_key, i, Fintern (new_it, Qnil));
	  SAFE_FREE ();
	}

      /* Check for match.  */
      found = lookup_key_1 (keymap, new_key, accept_default);
      if (!NILP (found) && !NUMBERP (found))
	break;
    }

  return found;
}