Amelio Vazquez-Reina
Amelio Vazquez-Reina

Reputation: 96274

Keyboard shortcuts in char run mode (ansi-term) in Emacs

I use WindMove in Emacs 24.1 to move around multiple windows using keyboard shortcuts:

(global-set-key (kbd "M-J") 'windmove-left)          ; move to window on the left
(global-set-key (kbd "M-L") 'windmove-right)         ; move "       "    the right
(global-set-key (kbd "M-I") 'windmove-up)            ; move "       "    above
(global-set-key (kbd "M-K") 'windmove-down);         ; move "       "    below

Is there a way to associate these WindMove keyboard shortcuts with char run mode on an ansi-term? I would like to avoid having to switch into line run mode for moving between windows. After a while it becomes tedious to type C-c C-k and C-c C-j back and forth to go into/leave the terminal.

Upvotes: 2

Views: 1242

Answers (2)

By default, term-char-mode forwards most keys to the terminal, without interpreting them within Emacs, which is why windmove keybindings are not working.

Here is a way to override the term-char-mode keymap to force windmove bindings to be interpreted instead of forwarded:

(eval-after-load "term"
  '(progn
     (define-key term-raw-map (kbd "M-J") 'windmove-left)
     (define-key term-raw-map (kbd "M-L") 'windmove-right)
     ;; ...
     ))

Upvotes: 2

dkim
dkim

Reputation: 3970

The code below will work for you. It uses the Emacs advising mechanism, which allows a user to dynamically change a function's behavior without modifying its source code directly. In this case, it is used to make the winmove-* functions run term-char-mode before executing their original definition. If you are also using other window-selecting functions, such as other-window, besides winmove-*, you can advise those functions in the same way. Refer to Advising Functions for details on the advising mechanism.

The code also handles the issue related to the term-raw-map keymap. term-raw-map is not defined until term.el is fully loaded (or M-xansi-term is executed). So you should add the (define-key term-raw-map ...) forms to the term-load-hook hook, which is automatically run when term.el is loaded, instead of putting them at the top level of the init file.

(global-set-key (kbd "M-J") 'windmove-left)
(global-set-key (kbd "M-L") 'windmove-right)
(global-set-key (kbd "M-I") 'windmove-up)
(global-set-key (kbd "M-K") 'windmove-down)

(defun ansi-term-char-mode ()
  (if (string= (buffer-name) "*ansi-term*")
    (term-char-mode)))

(defadvice windmove-left (before windmove-left-ansi-term (&optional arg))
  (ansi-term-char-mode))

(defadvice windmove-right (before windmove-right-ansi-term (&optional arg))
  (ansi-term-char-mode))

(defadvice windmove-up (before windmove-up-ansi-term (&optional arg))
  (ansi-term-char-mode))

(defadvice windmove-down (before windmove-down-ansi-term (&optional arg))
  (ansi-term-char-mode))

(add-hook 'term-load-hook
  (lambda ()
    (define-key term-raw-map (kbd "M-J") 'windmove-left)
    (ad-activate 'windmove-left)
    (define-key term-raw-map (kbd "M-L") 'windmove-right)
    (ad-activate 'windmove-right)
    (define-key term-raw-map (kbd "M-I") 'windmove-up)
    (ad-activate 'windmove-up)
    (define-key term-raw-map (kbd "M-K") 'windmove-down)
    (ad-activate 'windmove-down)))

Upvotes: 2

Related Questions