本节介绍用于创建按键映射的函数。
该函数创建并返回一个新的空稀疏按键映射(稀疏按键映射是日常使用中最常用的类型)。
与 make-keymap 不同,新创建的按键映射不包含字符表(char-table),且未绑定任何事件。
(make-sparse-keymap)
⇒ (keymap)
若指定了 prompt 参数,该值会成为按键映射的整体提示字符串。 此参数仅应在创建菜单按键映射时指定(see 定义菜单)。 带有整体提示字符串的按键映射在激活并用于查找下一个输入事件时, 总会弹出鼠标菜单或键盘菜单。不要为主模式或次要模式的主映射指定整体提示字符串, 否则命令循环会在每次执行时都弹出键盘菜单。
该函数创建并返回一个新的完整按键映射。
该按键映射包含一个字符表(see 字符表),
为所有无修饰符的字符分配了绑定槽位。新按键映射初始时将所有这些字符绑定为 nil,
且未绑定任何其他类型的事件。参数 prompt 的作用与 make-sparse-keymap 中相同,
用于指定提示字符串。
(make-keymap)
⇒ (keymap #^[nil nil keymap nil nil nil ...])
当需要存储大量绑定时,完整按键映射比稀疏按键映射效率更高; 而仅需少量绑定时,稀疏按键映射则更为合适。
你可以使用上述函数创建按键映射,
再通过 keymap-set(see 修改按键绑定)为该映射指定按键绑定。
但在编写模式时,常常需要一次性绑定大量按键,
逐个使用 keymap-set 会繁琐且易出错。
此时可使用 define-keymap,它能一次性完成按键映射的创建与多组按键的绑定。
以下是一个基础示例:
(define-keymap "n" #'forward-line "f" #'previous-line "C-c C-c" #'quit-window)
该函数会创建一个新的稀疏按键映射,在其中定义 pairs 中的按键绑定, 并返回这个新映射。若 pairs 中存在重复的按键绑定,函数会抛出错误。
pairs 是由按键绑定与按键定义交替组成的列表,格式与 keymap-set 接受的参数一致。
此外,按键可以是特殊符号 :menu,此时对应的定义应为 easy-menu-define 可接受的菜单定义
(see 简易菜单)。以下是该用法的简短示例:
(define-keymap :full t
"g" #'eww-reload
:menu '("Eww"
["Exit" quit-window t]
["Reload" eww-reload t]))
在按键/定义对之前,可使用若干关键字来修改新按键映射的特性。
若 define-keymap 调用中未指定某特性关键字,则该特性的默认值为 nil。
可用的特性关键字如下:
:full若值为非 nil,则创建字符表类型的按键映射(等效于 make-keymap),
而非稀疏按键映射(等效于 make-sparse-keymap,see 创建按键映射)。
默认创建稀疏按键映射。
:parent若值为非 nil,则其值应为一个按键映射,将被用作新映射的父映射(see 继承与按键映射表)。
:keymap若值为非 nil,则其值应为一个已存在的按键映射。此时函数不会创建新映射,
而是修改指定的现有映射。
:suppress若值为非 nil,则会通过 suppress-keymap 禁用该按键映射
(see 修改按键绑定)。默认情况下,数字键和减号键不会被禁用;
若该值为 nodigits,则数字键和减号键会与其他字符一样被禁用。
:name若值为非 nil,则其值应为一个字符串。当通过 x-popup-menu 将该映射用作菜单时,
该字符串会作为菜单名称(see Pop-Up Menus)。
:prefix若值为非 nil,则其值应为一个符号,将被用作前缀命令(see 前缀键)。
此时 define-keymap 返回该符号而非映射本身。
在实际使用中,按键映射最常见的用法是将其绑定到变量上。
几乎所有模式都会这么做——名为 foo 的模式通常会有一个名为 foo-mode-map 的变量。
该宏将 name 定义为变量,把 options 和 pairs 传递给 define-keymap,
并将返回结果设为该变量的默认值。若 pairs 中存在重复的按键绑定,宏会抛出错误。
options 的格式与 define-keymap 中的关键字一致,
但新增了 :doc 关键字,用于为定义的变量提供文档字符串。
示例如下:
(defvar-keymap eww-textarea-map :parent text-mode-map :doc "Keymap for the eww text area." "RET" #'forward-line "TAB" #'shr-next-link)
可通过为按键映射中的命令设置 repeat-map 属性,
将其标记为 ‘可重复执行’ (即可在 repeat-mode 中使用),示例如下:
(put 'undo 'repeat-map 'undo-repeat-map)
其中该属性的值为 repeat-mode 要使用的映射。
为避免重复调用 put 函数,defvar-keymap 还提供了 :repeat 关键字,
可用于指定映射中哪些命令可在 repeat-mode 中使用。
该关键字支持以下取值:
t表示映射中所有命令均可重复执行,这是最常用的用法。
(:enter (commands ...) :exit (commands ...) :hints ((command . "hint") ...))指定 :enter 列表中的命令会进入 repeat-mode,
:exit 列表中的命令会退出重复模式。
若 :enter 列表为空,则映射中所有命令都会进入 repeat-mode。
若需要为当前定义的映射中不存在、但需设置 repeat-map 属性的命令配置该特性,
可在该列表中指定这些命令。
若 :exit 列表为空,则映射中无命令会退出 repeat-mode。
若当前定义的映射中包含不应设置 repeat-map 属性的命令,
可在该列表中指定这些命令。
:hints 列表可包含 cons 对,其中首个元素(CAR)为命令,
第二个元素(CDR)为字符串,会在回显区中与可重复执行的按键一同显示。
例如,要让 u 重复执行 undo 命令,以下两段代码等效:
(defvar-keymap undo-repeat-map "u" #'undo) (put 'undo 'repeat-map 'undo-repeat-map)
和
(defvar-keymap undo-repeat-map :repeat t "u" #'undo)
当映射中有多个命令且均需设为可重复执行时,推荐使用后一种写法。
该函数返回 keymap 的副本。此函数几乎很少用到。 若你需要一个基于现有映射、仅做少量修改的新映射, 应使用映射继承而非复制,例如:
(let ((map (make-sparse-keymap))) (set-keymap-parent map <theirmap>) (keymap-set map ...) ...)
执行 copy-keymap 时,
直接作为 keymap 中绑定存在的所有按键映射都会被递归复制,
且递归层级无限制。但当某个字符的定义是一个函数定义为按键映射的符号时,
不会发生递归复制——该符号会直接出现在新副本中。
(setq map (copy-keymap (current-local-map))) ⇒ (keymap
;; (This implements meta characters.)
(27 keymap
(83 . center-paragraph)
(115 . center-line))
(9 . tab-to-tab-stop))
(eq map (current-local-map))
⇒ nil
(equal map (current-local-map))
⇒ t