Function: key-description

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

Signature

(key-description KEYS &optional PREFIX)

Documentation

Return a pretty description of key-sequence KEYS.

Optional arg PREFIX is the sequence of keys leading up to KEYS. For example, [?\C-x ?l] is converted into the string "C-x l".

For an approximate inverse of this, see kbd.

View in manual

Source Code

// Defined in /usr/src/emacs/src/keymap.c
{
  ptrdiff_t len = 0;
  Lisp_Object *args;
  EMACS_INT nkeys = XFIXNUM (Flength (keys));
  EMACS_INT nprefix = XFIXNUM (Flength (prefix));
  Lisp_Object sep = build_string (" ");
  bool add_meta = false;
  USE_SAFE_ALLOCA;

  /* This has one extra element at the end that we don't pass to Fconcat.  */
  ptrdiff_t size4;
  if (INT_MULTIPLY_WRAPV (nkeys + nprefix, 4, &size4))
    memory_full (SIZE_MAX);
  SAFE_ALLOCA_LISP (args, size4);

  /* In effect, this computes
     (mapconcat 'single-key-description keys " ")
     but we shouldn't use mapconcat because it can do GC.  */

  Lisp_Object lists[2] = { prefix, keys };
  ptrdiff_t listlens[2] = { nprefix, nkeys };
  for (int li = 0; li < ARRAYELTS (lists); li++)
    {
      Lisp_Object list = lists[li];
      ptrdiff_t listlen = listlens[li], i_byte = 0;

      if (! (NILP (list) || STRINGP (list) || VECTORP (list) || CONSP (list)))
	wrong_type_argument (Qarrayp, list);

      for (ptrdiff_t i = 0; i < listlen; )
	{
	  Lisp_Object key;
	  if (STRINGP (list))
	    {
	      int c = fetch_string_char_advance (list, &i, &i_byte);
	      if (SINGLE_BYTE_CHAR_P (c) && (c & 0200))
		c ^= 0200 | meta_modifier;
	      key = make_fixnum (c);
	    }
	  else if (VECTORP (list))
	    {
	      key = AREF (list, i);
	      i++;
	    }
	  else
	    {
	      key = XCAR (list);
	      list = XCDR (list);
	      i++;
	    }

	  if (add_meta)
	    {
	      if (!FIXNUMP (key)
		  || EQ (key, meta_prefix_char)
		  || (XFIXNUM (key) & meta_modifier))
		{
		  args[len++] = Fsingle_key_description (meta_prefix_char,
							 Qnil);
		  args[len++] = sep;
		  if (EQ (key, meta_prefix_char))
		    continue;
		}
	      else
		key = make_fixnum (XFIXNUM (key) | meta_modifier);
	      add_meta = false;
	    }
	  else if (EQ (key, meta_prefix_char))
	    {
	      add_meta = true;
	      continue;
	    }
	  args[len++] = Fsingle_key_description (key, Qnil);
	  args[len++] = sep;
	}
    }

  Lisp_Object result;
  if (add_meta)
    {
      args[len] = Fsingle_key_description (meta_prefix_char, Qnil);
      result = Fconcat (len + 1, args);
    }
  else if (len == 0)
    result = empty_unibyte_string;
  else
    result = Fconcat (len - 1, args);
  SAFE_FREE ();
  return result;
}