key-chord.el を読む(前編)。
key-chord.el は何度も言うけど、修飾キー以外の2つのキーの組み合わせで、関数を発動するというゲームコマンドの様なキーバインドを提供してくれるマイナーモードです。
んで、僕はkey-chord で実行するコマンドに引数を渡したいのですが、できれば、その引数をタイプした文字を渡したいと思っているのですが、その方法がよく分からないので、key-chord.el を読んでみる事にしました。
初期設定値。
(defvar key-chord-two-keys-delay 0.1 ; 0.05 or 0.1 "Max time delay between two key press to be considered a key chord.") (defvar key-chord-one-key-delay 0.2 ; 0.2 or 0.3 to avoid first autorepeat "Max time delay between two press of the same key to be considered a key chord. This should normally be a little longer than `key-chord-two-keys-delay'.")
最初の初期値の部分。two-keys-delay は2つの異なるキーをタイプして発動する場合のその間隔の秒数。初期値は0.1秒とけっこう長いので、ちょっと縮めた方が無難かも。
one-key-delay は、同じキーの2度押しで発動する場合の間隔。こっちはまぁ短かい方が誤動作しなくて良いかも。
んで、実際に自分で設定する場合には、
(setq key-chord-two-keys-delay 0.08)
という感じに設定すんですが、なんで key-chord.el 本体では、defvar で変数が定義してあって、自分の設定では setq 使うんかを調べてみたら、defvar は通常様々なプログラムで変更される値を与えるそうな。
んでもって、setq はシンボルの値を変更するもっとも手軽な方法だとかで。defvar は説明文も書く事ができる。グローバル変数、シンボルの値を参照/変更する
モードのオンオフ
ちょっと飛ばして、モードの定義の部分。
(defvar key-chord-mode nil) ;; 中略 (defun key-chord-mode (arg) "Toggle key chord mode. With positive ARG enable the mode. With zero or negative arg disable the mode. A key chord is two keys that are pressed simultaneously, or one key quickly pressed twice. See functions `key-chord-define-global' or `key-chord-define' and variables `key-chord-two-keys-delay' and `key-chord-one-key-delay'." (interactive "P") (setq key-chord-mode (if arg (> (prefix-numeric-value arg) 0) (not key-chord-mode))) (cond (key-chord-mode (setq input-method-function 'key-chord-input-method) (message "Key Chord mode on")) (t (setq input-method-function nil) (message "Key Chord mode off"))))
まず、key-chord-mode という変数と関数があるのに注意。むお?っと思ったけど、そういうのはプログラムでは良くある話なので、あまり気にしない。
でも一応調べてみると、Lisp勉強中(2) 変数と関数とシンボルに詳しい説明があった。
key-chord-mode関数の方は、interactive "P" である。interactive は対話的、つまりコマンドとして呼び出す事ができるんですが、"P" って何?となるわけです。P が一番良く見る気がしますけどね。
interactiveのコード文字によると、それぞれのコード文字の指定によって、引数arg-descriptorを interactive を含む関数に渡す。
P は生の前置引数で入出力はなし。意味分からん。が、何も渡さず、すでにある値を使うといった感じか。
呼び出されたら、さっそく key-chord-mode 変数に何やら複雑なものを代入している。たぶん、key-chord-mode が nil 以外であれば、nil を。nil であれば、t を返す感じか。トグル部分だと思うが、もう眠いのでよくわかんない。条件: if, cond, not など、前置コマンド引数 prefix-numeric-value arg など。。
んでまぁ、それぞれの状態をメッセージで出すと。
キーマップ定義部分。
(defun key-chord-define-global (keys command) (interactive "sSet key chord globally (2 keys): \nCSet chord \"%s\" to command: ") (key-chord-define (current-global-map) keys command))
まず、グローバルなキーマップを設定する関数。インタラクティブにも起動でき、対話的にキーバインドとコマンドを定義できる。知らんかったー。
定義したキーバインドは (current-global-map) と一緒に key-chord-define() 関数へ渡されるのだが、current-global-map ってのは、組込みのモヨー。
scratch で評価してみたら、なんか色々なキーマップがどばーっと出てきたので、読んだ通り、現在のグローバルキーマップって所だろう。
(defun key-chord-define (keymap keys command) (if (/= 2 (length keys)) (error "Key-chord keys must have two elements")) ;; Exotic chars in a string are >255 but define-key wants 128..255 for those (let ((key1 (logand 255 (aref keys 0))) (key2 (logand 255 (aref keys 1)))) (if (eq key1 key2) (define-key keymap (vector 'key-chord key1 key2) command) ;; else (define-key keymap (vector 'key-chord key1 key2) command) (define-key keymap (vector 'key-chord key2 key1) command))))
んで、key-chord-define() に渡されてからどうなるかというと、まずkeysが2文字じゃないものはエラーを出します。
次に、よく分からない関数で、keys が分解され、1文字目を key1、2文字目を key2 変数に入れています。
んでもって、正式に keymap として追加する様ですが、key1 と key2 が一緒であれば一個だけを。異なっていれば、逆順も追加している様です。これで、微妙な同時押しに対処しているわけですね。
続きは次回。
思ったよりも長くなったので、とりあえず持ち越し。
defadvice が火を吹くぜ。