Shift-arrow not working in emacs within tmux

12,419

Solution 1

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.

Solution 2

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

Solution 3

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.

Share:
12,419

Related videos on Youtube

triangle_man
Author by

triangle_man

Updated on September 18, 2022

Comments

  • triangle_man
    triangle_man over 1 year

    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?

    • Admin
      Admin over 12 years
      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
    • Admin
      Admin over 12 years
      Try to vote to close question if you really can't
  • ephemient
    ephemient about 12 years
    See Fix Terminals - Please for a proposal to standardize some of these differences/deficiencies in terminal input. It's been raised on iterm2-discuss but I don't think anybody's implemented it yet.
  • slm
    slm almost 10 years
    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)."
  • William Hilton
    William Hilton almost 9 years
    This is exactly what I needed to use textadept in tmux.
  • gogators
    gogators almost 8 years
    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.
  • avp
    avp over 7 years
    Ctrl+Shift does not work, Ctrl+<f#> does not work and so on. Ctrl+d does work though.
  • jhegedus
    jhegedus about 7 years
    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.)
  • andras.tim
    andras.tim over 6 years
    this solution don't work if the TERM in tmux is not xterm (e.g. Shift+F6 in mc doing F15 when TERM=screen-256color...)