6

I'm using the Dvorak keyboard layout and have swapped C-x and C-t, because I find it easier to type on Dvorak.

(define-key key-translation-map [?\C-x] [?\C-t])
(define-key key-translation-map [?\C-t] [?\C-x])

I'm also using god-mode, though, so I'd like x to be swapped with t when in god-local-mode, such that typing x results in C-t and typing t results in C-x. I have a very crude solution using keyboard-translate:

(defun my-god-swap-on ()
  (interactive)
  (keyboard-translate ?x ?t)
  (keyboard-translate ?t ?x))

(defun my-god-swap-off ()
  (interactive)
  (aset keyboard-translate-table ?t nil)
  (aset keyboard-translate-table ?x nil))

(add-hook 'god-mode-enabled-hook 'my-god-swap-on)
(add-hook 'god-mode-disabled-hook 'my-god-swap-off)

Although this works it is extremely inelegant as it modifies global state. If I switched to a buffer where god-mode is not enabled, the translation would still be active. I could add yet another hook for buffer switching to make sure that the translation is disabled when god-local-mode is inactive in the current buffer, but this seems like a very ugly mitigation technique.

Is it possible to restrict the effects to a keyboard translation to only a single minor mode?

If this is not possible, is there another more elegant way I could swap keys in god-mode? I see that god-mode rewires all keys bound to self-insert-command to god-mode-self-insert, but this uses this-command-keys-vector to determine with what key it was called and I cannot seem to shadow the definition of this-command-keys-vector with a let binding to swap x and t in a wrapper before passing control to god-mode-self-insert.

5

FWIW, here's your solution in 'before' advice form:

n.b. this is untested (I don't use god-mode).

(defadvice god-mode-lookup-key-sequence (before my-swap-x-t)
  "Swap ?x and ?t KEY arguments."
  (case (ad-get-arg 0)
    (?x (ad-set-arg 0 ?t))
    (?t (ad-set-arg 0 ?x))))
(ad-activate 'god-mode-lookup-key-sequence)
  • This is exactly what I was looking for. I knew there had to be a way to achieve this by advising the function, but I didn't know exactly how to do it. Thanks! – rekado Nov 1 '14 at 4:01
2

The general solution is to modify god-mode so that it takes the key translation mechanism into account. This way, it will work with any key translation you've set or will set (C-h causing DEL is another common one).

I had the same problem so I filed a bug and wrote a patch that fixes it, at least for C- combinations. It changes the last sexp of key-string-after-consuming-key from:

(if key-string-so-far
    (concat key-string-so-far " " next-modifier next-key)
  (concat next-modifier next-key))

To:

(let* ((next-literal-key-string (concat next-modifier next-key))
       (translation (lookup-key key-translation-map
                                (read-kbd-macro next-literal-key-string t)))
       (next-interpreted-key-string
        (if translation
            (format-kbd-macro translation)
          next-literal-key-string)))

  (if key-string-so-far
      (concat key-string-so-far " " next-interpreted-key-string)
    next-interpreted-key-string))
1

I now use this:

(defun original-god-mode-lookup-key-sequence (&optional key key-string-so-far) ())
(fset 'original-god-mode-lookup-key-sequence (symbol-function 'god-mode-lookup-key-sequence))

(defun god-mode-lookup-key-sequence (&optional key key-string-so-far)
  "Wrap original-god-mode-lookup-key-sequence.  Swap x and t."
  (interactive)
  (case key
    (?x (original-god-mode-lookup-key-sequence ?t key-string-so-far))
    (?t (original-god-mode-lookup-key-sequence ?x key-string-so-far))
    (t (original-god-mode-lookup-key-sequence key key-string-so-far))))

It makes a copy of god-mode-lookup-key-sequence as original-god-mode-lookup-key-sequence and then overrides it with a wrapper that performs the swap for x and t. It's not elegant, but at least it won't leak.

  • Maybe (defalias 'bar (symbol-function 'foo)) would be a simpler start? – phils Oct 31 '14 at 23:55
  • 1
    It seems like a use-case for some 'before' advice, though. It could just change the argument if necessary, before the original function executes. – phils Oct 31 '14 at 23:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.