2

我正在尝试定义我的次要模式,然后模仿它isearch-mode(因为它是一种交互式搜索和替换工具,我认为它可能是一个很好的起点)。我的命令运行良好(在全局键绑定上测试),但我在将它们本地(在次要模式映射中)绑定到某些键(即 TAB 和 RET)时遇到严重问题。我正在做这样的事情:

(defvar my-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\s" 'my-command)
    (define-key map "\t" 'another-one)
    (define-key map "\r" 'yet-another)
    map))

(当然,我确实将我的键盘映射放入了 minor-mode-map-alist。)

虽然 space-bound 命令工作正常,但 TAB 和 RET 不知何故不能。如果我将例如“\t”更改为“[f11]”,它工作正常。我尝试使用具有相同结果的“矢量符号”([?\t])(在 Ch Cv-ing 我的键盘映射之后,这并不奇怪)。可能会发生什么?

编辑:为了澄清问题,我试图将其隔离并提出以下代码。假设我想要一个人工的、相当最小的次要模式tabbang,其中 TAB 键插入一个感叹号。我正在这样做:

(defvar tabbang-mode)
(add-to-list 'minor-mode-alist '(tabbang-mode tabbang-mode) t)

(defvar tabbang-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [?\t] 'tabbang-insert-bang)
    (define-key map [?\C-\t] 'tabbang-insert-bang)
    (define-key map [f11] 'tabbang-insert-bang)
    (define-key map [?\r] 'tabbang-done)
    (define-key map [t] 'tabbang-other-char)
    map))
(add-to-list 'minor-mode-map-alist `(tabbang-mode . ,tabbang-mode-map) t)

(defun tabbang-insert-bang ()
  (interactive)
  (insert "!"))

(defun tabbang-mode ()
  (interactive)
  (setq tabbang-mode " tabbang"))

(defun tabbang-other-char ()
  (interactive)
  (tabbang-done)
  (setq unread-command-events
    (append (listify-key-sequence (this-command-keys))
        unread-command-events)))

(defun tabbang-done ()
  (interactive)
  (setq tabbang-mode nil))

虽然在我tabbang-mode的“其他”键正确退出模式并插入自己,f11 插入一个砰(正确),TAB 不退出模式(正确),但什么都不插入(错误),C-TAB 产生“未定义键”错误(绝对错误),并且 RET 退出模式(正确),但插入换行符(错误)。我尝试了一个“新”的 emacs(没有加载站点文件和我的 .emacs),所以没有其他代码应该干预(我害怕 yasnippet 以某种方式捕获 TAB 等)这是怎么回事?

4

3 回答 3

5

我相信你可以分别用“\t”和“\r”来改变(kbd "<tab>")它们(kbd "<return>")


作为对您的编辑的回应,是的,以下内容非常适合我:

...
(defvar tabbang-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "<tab>") 'tabbang-insert-bang)
    (define-key map (kbd "<C-tab>") 'tabbang-insert-bang)
    (define-key map (kbd "<f11>") 'tabbang-insert-bang)
    (define-key map (kbd "<return>") 'tabbang-done)
    (define-key map (kbd "t") 'tabbang-other-char)
    map))
(add-to-list 'minor-mode-map-alist `(tabbang-mode . ,tabbang-mode-map) t)
...
于 2012-02-04T04:31:24.340 回答
3

问题如下:某些键通过功能键映射进行翻译,该映射仅在键未绑定时才执行翻译。例如,当您点击 TAB 键时,在 GUI 下生成的 [tab] 事件,如果没有绑定到 [tab],则被转换为 [?\t]。[return] 也是如此,它被映射到 [?\r]。现在的问题是你的包罗万象的 [t] 绑定意味着任何键序列都有一个绑定,所以 [tab] 不再重新映射到 [?\t] 。isearch 遇到同样的问题,请参阅我们在 isearch-other-meta-char 中所做的扭曲。

我认为解决这个问题的正确方法是避免 [t] 绑定,而是以不同的方式实现“任何其他键的退出模式”(我现在的经验法则是:“如果你需要把东西放回未读状态-command-events,你可能做错了”)。一种方法是使用 pre-command-hook 来检查 `this-command' 是否是您的命令之一,或者 (this-command-keys-vector) 是否绑定在您的键盘映射中。在 Emacs-24 中,对于这些用途,我们可能会有类似下面的代码:

(defun set-temporary-overlay-map (map &optional keep-pred)
  (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map"))
         (overlaysym (make-symbol "t"))
         (alist (list (cons overlaysym map)))
         (clearfun
          `(lambda ()
             (unless ,(cond ((null keep-pred) nil)
                            ((eq t keep-pred)
                             `(eq this-command
                                  (lookup-key ',map
                                              (this-command-keys-vector))))
                            (t `(funcall ',keep-pred)))
               (remove-hook 'pre-command-hook ',clearfunsym)
               (setq emulation-mode-map-alists
                     (delq ',alist emulation-mode-map-alists))))))
    (set overlaysym overlaysym)
    (fset clearfunsym clearfun)
    (add-hook 'pre-command-hook clearfunsym)
    (push alist emulation-mode-map-alists)))
于 2012-02-08T21:29:29.333 回答
0

字符串“tab”(即您使用 得到的"\t")与有效的键名不对应。你想要类似"\C-i"标签和"\C-j"换行符的东西。

于 2012-02-04T10:48:19.193 回答