26

I recently started using tmux (was a screen user before) and I'm loving it, except for one small problem. I use emacs within my tmux session and I am used to using Shift-arrow keys to move between emacs windows (not tmux windows). When running within tmux, these bindings seem to stop working entirely (it's like they don't register to emacs at all). If I exit tmux and just run emacs in my shell, they work fine.

I'm using iTerm2, ssh'd into a Linux box, running tmux/emacs there. I have the Shift-arrow key bindings set up as follows in my .emacs:

(global-set-key "\M-[1;2A" 'windmove-up)
(global-set-key "\M-[1;2B" 'windmove-down)
(global-set-key "\M-[1;2C" 'windmove-right)
(global-set-key "\M-[1;2D" 'windmove-left)

When not running in tmux, I can confirm those are the right character sequences for the shift-arrow key combinations by doing C-q in emacs and then pressing the key sequence. Within tmux, even that doesn't work because it doesn't seem to see any input from the shift-arrow keypress (it just sits at the C-q prompt).

Looking at the key bindings for tmux, I don't think anything is bound to Shift-arrow keys and even if it was, they would only register after entering the prefix (which is bound to C-o in my case).

Any idea on how to make the shift-arrow keys work again within tmux?

  • 1
    I actually found the answer this myself but StackExchange won't let me officially answer my own question for another 7 hours as I don't have enough reputation yet. Anyway if anyone is interested, doing set-window-option xterm-keys on seems to fix it. I set this as a global option by putting this in my .tmux.conf and I seem to be back in business: set-window-option -g xterm-keys on – triangle_man Nov 11 '11 at 18:21
  • Try to vote to close question if you really can't – Eir Nym Nov 19 '11 at 15:05
13

First, make sure your TERM is correct at each location:

  • xterm-something (e.g. xterm-256color) inside your local shell running in your iTerm2 window
  • xterm-something inside your shell after SSHing to the Linux system
    This should be the same as whatever you are using locally in iTerm2, since SSH should be passing it along to the remote side (and, importantly, the remote side should not be blindly overriding the value in a shell initialization file).
  • screen-something (e.g. screen-256color) inside your shell running under tmux on the Linux system
    You should always use a screen-based TERM inside tmux.

Having an xterm TERM immediately outside tmux will allow tmux to recognize the modified arrow keys, but it will not pass them through unless you also have its xterm-keys window option turned on. Put this in your ~/.tmux.conf on the Linux system:

set-window-option -g xterm-keys on

The sequences for the shifted keys should now make it through to Emacs, running inside tmux, across an SSH connection, inside an iTerm2 window.

  • This is exactly what I needed to use textadept in tmux. – William Hilton Jul 9 '15 at 2:58
  • 1
    This solution did not work for me. I'm on Fedora-23 using a gnome-terminal. My TERM's and .tmux.conf are set as described in the answer. Setting the bindings as described in the question does work however. I'd really like to solve this mystery since it's also mucking up a ncurses app I'm working on. – gogators Jun 28 '16 at 19:31
  • 1
    @gogators same here; the above solution does not work for me even though I had exactly what was suggested. – Fingolfin Jun 29 '16 at 21:09
  • Ctrl+Shift does not work, Ctrl+<f#> does not work and so on. Ctrl+d does work though. – avp Nov 16 '16 at 15:30
  • In practice this means: export XTERM=xterm-256color (I am writing this becasue I did not know what "your TERM" in the answer means, I was looking for a comment explaining that... there was none, and now there is one.) – jhegedus Feb 27 '17 at 21:03
3

First you must enable xterm-keys in your tmux config. So put the following in ~/.tmux.conf

setw -g xterm-keys on

But, this will break other key combinations. To fix them, put the following in your~/.emacs or ~/.emacs.d/init.el config

;; handle tmux's xterm-keys
;; put the following line in your ~/.tmux.conf:
;;   setw -g xterm-keys on
(if (getenv "TMUX")
    (progn
      (let ((x 2) (tkey ""))
    (while (<= x 8)
      ;; shift
      (if (= x 2)
          (setq tkey "S-"))
      ;; alt
      (if (= x 3)
          (setq tkey "M-"))
      ;; alt + shift
      (if (= x 4)
          (setq tkey "M-S-"))
      ;; ctrl
      (if (= x 5)
          (setq tkey "C-"))
      ;; ctrl + shift
      (if (= x 6)
          (setq tkey "C-S-"))
      ;; ctrl + alt
      (if (= x 7)
          (setq tkey "C-M-"))
      ;; ctrl + alt + shift
      (if (= x 8)
          (setq tkey "C-M-S-"))

      ;; arrows
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d A" x)) (kbd (format "%s<up>" tkey)))
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d B" x)) (kbd (format "%s<down>" tkey)))
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d C" x)) (kbd (format "%s<right>" tkey)))
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d D" x)) (kbd (format "%s<left>" tkey)))
      ;; home
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d H" x)) (kbd (format "%s<home>" tkey)))
      ;; end
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d F" x)) (kbd (format "%s<end>" tkey)))
      ;; page up
      (define-key key-translation-map (kbd (format "M-[ 5 ; %d ~" x)) (kbd (format "%s<prior>" tkey)))
      ;; page down
      (define-key key-translation-map (kbd (format "M-[ 6 ; %d ~" x)) (kbd (format "%s<next>" tkey)))
      ;; insert
      (define-key key-translation-map (kbd (format "M-[ 2 ; %d ~" x)) (kbd (format "%s<delete>" tkey)))
      ;; delete
      (define-key key-translation-map (kbd (format "M-[ 3 ; %d ~" x)) (kbd (format "%s<delete>" tkey)))
      ;; f1
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d P" x)) (kbd (format "%s<f1>" tkey)))
      ;; f2
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d Q" x)) (kbd (format "%s<f2>" tkey)))
      ;; f3
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d R" x)) (kbd (format "%s<f3>" tkey)))
      ;; f4
      (define-key key-translation-map (kbd (format "M-[ 1 ; %d S" x)) (kbd (format "%s<f4>" tkey)))
      ;; f5
      (define-key key-translation-map (kbd (format "M-[ 15 ; %d ~" x)) (kbd (format "%s<f5>" tkey)))
      ;; f6
      (define-key key-translation-map (kbd (format "M-[ 17 ; %d ~" x)) (kbd (format "%s<f6>" tkey)))
      ;; f7
      (define-key key-translation-map (kbd (format "M-[ 18 ; %d ~" x)) (kbd (format "%s<f7>" tkey)))
      ;; f8
      (define-key key-translation-map (kbd (format "M-[ 19 ; %d ~" x)) (kbd (format "%s<f8>" tkey)))
      ;; f9
      (define-key key-translation-map (kbd (format "M-[ 20 ; %d ~" x)) (kbd (format "%s<f9>" tkey)))
      ;; f10
      (define-key key-translation-map (kbd (format "M-[ 21 ; %d ~" x)) (kbd (format "%s<f10>" tkey)))
      ;; f11
      (define-key key-translation-map (kbd (format "M-[ 23 ; %d ~" x)) (kbd (format "%s<f11>" tkey)))
      ;; f12
      (define-key key-translation-map (kbd (format "M-[ 24 ; %d ~" x)) (kbd (format "%s<f12>" tkey)))
      ;; f13
      (define-key key-translation-map (kbd (format "M-[ 25 ; %d ~" x)) (kbd (format "%s<f13>" tkey)))
      ;; f14
      (define-key key-translation-map (kbd (format "M-[ 26 ; %d ~" x)) (kbd (format "%s<f14>" tkey)))
      ;; f15
      (define-key key-translation-map (kbd (format "M-[ 28 ; %d ~" x)) (kbd (format "%s<f15>" tkey)))
      ;; f16
      (define-key key-translation-map (kbd (format "M-[ 29 ; %d ~" x)) (kbd (format "%s<f16>" tkey)))
      ;; f17
      (define-key key-translation-map (kbd (format "M-[ 31 ; %d ~" x)) (kbd (format "%s<f17>" tkey)))
      ;; f18
      (define-key key-translation-map (kbd (format "M-[ 32 ; %d ~" x)) (kbd (format "%s<f18>" tkey)))
      ;; f19
      (define-key key-translation-map (kbd (format "M-[ 33 ; %d ~" x)) (kbd (format "%s<f19>" tkey)))
      ;; f20
      (define-key key-translation-map (kbd (format "M-[ 34 ; %d ~" x)) (kbd (format "%s<f20>" tkey)))

      (setq x (+ x 1))
      ))
    )
  )      

Also I have my solution in archlinux wiki

  • comment left by @JeffKlukas: "oblique's answer is just what I needed to get this working through PuTTY on Windows as well (I don't have the reputation to add this as a comment, so making an answer instead). When I turned on the xterm-keys option in tmux, Shift-arrow would produce text like 2C in emacs. By adding the above elisp code to my init.el, I get the expected functionality (especially useful in org mode)." – slm Jun 4 '14 at 14:23
1

tmux FAQ used to contain the following entry:

How do I make ctrl and shift arrow keys work in emacs?

The terminal-init-screen function in term/screen.el is called for new frames, but it doesn't configure any function keys.

If the tmux xterm-keys option is on, it is enough to define the same keys as xterm. Add the following to init.el or .emacs to do this:

(defadvice terminal-init-screen
  ;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
  (before tmux activate)
  ;; Docstring.  This describes the advice and is made available inside emacs;
  ;; for example when doing C-h f terminal-init-screen RET
  "Apply xterm keymap, allowing use of keys passed through tmux."
  ;; This is the elisp code that is run before `terminal-init-screen'.
  (if (getenv "TMUX")
    (let ((map (copy-keymap xterm-function-map)))
    (set-keymap-parent map (keymap-parent input-decode-map))
    (set-keymap-parent input-decode-map map))))

And ensure .tmux.conf contains "set -g xterm-keys on".

Alternatively, the screen.el file can be copied to the load path and customized.

I opened tmux issue #1349 to request restore for the FAQ entry.

0

In general case, problems like this happen because of mistmatch between what the terminal emulator sends and what the client application expects.

Different terminal emulators have different degree of customizability, so familiarizing oneself with emulation tunables of a particular one is necessary.

Client applications depend on value of $TERM which is used to lookup terminal (emulator)'s capabilities in the terminfo (or termcap) database.

In your case, your emacs bindings use explicit sequences thus $TERM and terminfo are irrelevant: a specific terminal emulator is expected - as you already figured out, a xterm-compatible one.

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.