Emacsでキーバインディングをグローバルにオーバーライドする


100

そのキーの他のすべてのバインディングをオーバーライドして優先するキーバインディングを設定するにはどうすればよいですか?すべてのメジャー/マイナーモードマップを上書きし、バインディングが常に有効であることを確認したい。

もちろんこれは動作しません:

(global-set-key "\C-i" 'some-function)

で動作しtext-modeますがlisp-mode、使用するC-iとリバウンドしlisp-indent-lineます。

lisp-mode他のすべてのモードでこのバインディングを個別に実行してオーバーライドできますが、もっと簡単な方法があるはずです。新しいファイルタイプの新しいモードをインストールするたびに、戻って、すべてのキーバインディングが新しいモードによってオーバーライドされていないことを確認する必要があります。

私がこれをしたいのは、他のエディターから既に習得してきたバインディングをエミュレートしたいからです。

回答:


149

私はすべての「オーバーライド」キーバインディングにマイナーモードを使用しています。

(defvar my-keys-minor-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-i") 'some-function)
    map)
  "my-keys-minor-mode keymap.")

(define-minor-mode my-keys-minor-mode
  "A minor mode so that my key settings override annoying major modes."
  :init-value t
  :lighter " my-keys")

(my-keys-minor-mode 1)

これには、他の誰かがキーボードを操作している場合や、デフォルトのキーバインディングの動作を確認する必要がある場合に、すべての変更を一度にオフにできる(マイナーモードを無効にする)ことができるという利点もあります。

ミニバッファーでこれをオフにする必要があるかもしれないことに注意してください:

(defun my-minibuffer-setup-hook ()
  (my-keys-minor-mode 0))

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)

1
これは良い考えのようです。マイナーモードが他のマイナーモードと戦わないようにする方法はありますか?
ブライアンカーパー

3
マイナーモードがマイナーモードリストの最初にあることを確認してください。
トレイジャクソン

2
トレイは正しいです。通常、これを.emacsの終わり近くに置くだけで十分です。また、オーバーライドするほとんどのバインディングは、メジャーモードが設定しているバインディングです。マイナーモードは通常、邪魔になりません。
scottfrazer 2009年

このアプローチに従いましたが、CiにバインドしたものはすべてTABキーにもバインドされることに気付きました。助言がありますか?
スティーブ

3
ブライアンCarper:ここではその後にロードされたマイナーモードに対処するための拡張機能です:stackoverflow.com/questions/683425/...は
PHILS

30

scottfrazerの回答に加えて、後でロードされるライブラリが独自の新しいキーマップを持ってくる場合でも、キーバインディングが優先されるように、以下を書きました。

キーマップはコンパイル時に生成できるため、loadこれを行うのに最適な場所のように思われました。

(add-hook 'after-load-functions 'my-keys-have-priority)

(defun my-keys-have-priority (_file)
  "Try to ensure that my keybindings retain priority over other minor modes.

Called via the `after-load-functions' special hook."
  (unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
    (let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
      (assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
      (add-to-list 'minor-mode-map-alist mykeys))))

スクリプトを貼り付けましたが、影響はありませんでした:(
alper

@alper実際に使用しているコードや問題を再現するための具体的な例/レシピなど、関連するすべての詳細を含めて質問を投稿することをお勧めします。
phils

21

use-packageevalをインストールして完了です。

(require 'bind-key)
(bind-key* "C-i" 'some-function)

5
use-packageはbind-keyに依存しますが、ユースケースにはbind-keyのみをインストールするだけで十分です。
xuchunyang

2
これ( 'bind-key'パッケージ)が最も便利なソリューションのようです。共有してくれてありがとう。
オリジロ2016

一致するものが見つかりませんでしたuse-packageInstall package: use-package [No Match]
alper

14

「emacs undefine org mode keybindings」を検索しているときにこの質問を見つけました。既存のCc Cb動作をバインド解除して、私のグローバルマップが組織バッファーで動作するようにbury-bufferを機能させたいからです。

これは私にとって最も簡単な解決策になりました:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))

1
これはモード固有であり、単一のユースケースでは機能しますが、全体像には対応していません。
RichieHH

12

scottfrazerの答えはまさにあなたが求めていたものですが、後世のために別の解決策について述べます。

Emacsマニュアルから:

「Ccの文字をLispプログラムのキーとして定義しないでください。Ccと文字(大文字または小文字)からなるシーケンスはユーザー用に予約されています。これらはユーザー用に予約された唯一のシーケンスなので、ブロックしないでください。」

個人のグローバルバインディングをCcに加えて文字にバインドする場合、安全である必要があります。ただし、これは単なる慣例であり、どのモードでもバインドをオーバーライドできます。


3
すべてのモードの中で、org-modeがこのルールに違反するとは思っていませんでした。「Cc Ch」は、Cc a、b、c、およびlがそれぞれorg-agenda、org-iswitchb、org-capture、およびorg-store-linkにバインドされていることを教えてくれます。
ネイトパーソンズ

7
Afaik、これらをバインドすることは、それを使用するためにorg-modeが提案する最初のステップですが、ユーザーはそれらを自分で定義する必要があります(つまり、デフォルトでは行われません)。(また、これらのバインディングはグローバルであり、組織のメジャーモードにバインドされていないためです)
Nikana Reklawyks

3

「特定のモードマップに対して明示的にオーバーライドしない限り、常にマップでキーバインドを使用する」場合、およびscottfrazierのアプローチを使用していると想定すると、次のようになります。

(defun locally-override (key cmd)
  (unless (local-variable-p 'my-keys-minor-mode-map)
    (set (make-variable-buffer-local 'my-keys-minor-mode-map)
         (make-sparse-keymap))
    (set-keymap-parent my-keys-minor-mode-map 
                       (default-value 'my-keys-minor-mode-map)))
  (define-key my-keys-minor-mode-map key cmd))

そう

(locally-override "\C-i" nil)

現在のバッファのマイナーモードからのみ「\ Ci」バインディングを削除する必要があります。警告:これは完全にテストされていませんが、適切なアプローチのようです。my-keys-minor-mode-mapのグローバル値を単に対処するのではなく、親を設定することのポイントは、グローバル値への以降の変更がローカル値に自動的に反映されるようにすることです。


2

できないと思います。これは、関数内のローカル変数宣言で非表示にできないグローバル変数を定義することを宣言することとほぼ同じです。スコープはそのようには機能しません。

ただし、elisp関数を作成してモードリストを調べ、すべての関数に再割り当てする方法があるかもしれません。


このスコープの考え方は技術的には正しいですが、overriding-local-map他のすべてのマップをオーバーライドするように特別に設計されています。しかし、それを使用するのは危険です。
event_jr 14

2

あなたが本当に自分でこれをしたいのでない限り、あなたは周りをチェックして、他の誰かがすでにそれをしていないかどうか見るべきです。

Emacsには、ウィンドウのようなキーバインドを提供するパッケージがあります。あなたはグーグルを通じてそれを見つけることができるはずです。


4
あなたが考えているパッケージはおそらくcua-modeです。
ドリュー

1
はい、それがパッケージです。
JesperE 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.