5

(windmove-default-keybindings 'meta) provides commands to move between emacs windows (eg M-<up> to move up a window). They are working fine for me when emacs -nw is run in a terminal, but in tmux they fail.

The individual commands work, eg winmove-up; and when run they tell me:

You can run the command winmove-up with M-<up>

But to M-<up> itself, I get:

ESC <up> is undefined

Same problem with any other prefix key (shift, control).

This is in tmux 1.9a/emacs 23.3.1 and tmux 2.0/emacs 24.5.1 under Ubuntu 12.04 and 14.04 respectively. In the first case I'm using "gnome-terminal". In the second ... I'm ssh'ing into a server and the TERM environment variable is "xterm". Once I start tmux, it becomes "screen-256color"; that's because I've used set -g default-terminal

Ideas?

Diagon
  • 473
  • 5
  • 16
  • They don't even work for me in putty. What terminal are you using? – Random832 Dec 04 '15 at 14:28
  • gnome-terminal for my home machine. When I ssh in to the server, the TERM environment variable says "xterm", and when I start tmux it's "screen-256color". I'll add it, above. – Diagon Dec 05 '15 at 05:30
  • I added more information to my answer, about adding new terminal types `screen-xtermkeys-256color` and `tmux-xtermkeys-256color`. – Random832 Dec 06 '15 at 00:31

3 Answers3

4

With help from @Random832, the answer to this question and the first answer to this one, along with some useful information about how emacs handles function keys in the answer to this question, there are two approaches:

Approach #1: In your .tmux.conf, use xterm-keys on, but also, if you are using 256 colors, then set your default-terminal correctly:

set -g xterm-keys on
set -g default-terminal "xterm-256color"

Approach #2: At a terminal, run cat and then type M-<up> etc to find the output. In my case it was: ^[[1;3A (and B & C & D). Then, use this code in your .emacs file:

(add-hook 'term-setup-hook
  '(lambda ()
     (define-key function-key-map "\e[1;3A" [M-up])
     (define-key function-key-map "\e[1;3B" [M-down])
     (define-key function-key-map "\e[1;3C" [M-right])
     (define-key function-key-map "\e[1;3D" [M-left])))

Note that this second approach also works for other prefix keys (Shift, Control) and that this same problem appears in screen.

Also note that all seems to work well except for in the gnus article summary buffer, where M-<up> and M-<dn> behave like <up> and <dn> (though M-<rt> and M-<lft> work fine).

Community
  • 1
  • 1
Diagon
  • 473
  • 5
  • 16
  • There are various other reasons not to use xterm-256color. I'll have an update later today to give a custom terminfo entry. – Random832 Dec 06 '15 at 00:11
  • 1
    Thanks! I've tried a myriad of ways to remap these keys (I'm using screen and have the same problem), and your approach #2 was the only way I've tried that actually worked. You saved me from a lifetime of frustration! – wvdschel Mar 25 '16 at 09:59
2

Emacs doesn't always properly translate modifiers on function keys.

First, see if the tmux option set -g xterm-keys on makes any difference. (This may require a new terminfo entry to fully work; if it makes any change at all even to say something other than ESC <up> please say in a comment)

Also, without xterm-keys on, try the key translations from this answer:

(define-key input-decode-map "\e\eOA" (kbd "<M-up>"))
(define-key input-decode-map "\e\eOB" (kbd "<M-down>"))

The xterm-keys solution has the advantage that, if it works, it will also work for shift and ctrl.

Instead of modifying the function-key-map, with xterm-keys on you can install a new terminfo entry with the appropriate keys:

# Note: tmux does translate Home and End (\EOH, \EOF) to \E[1~, \E[4~
# But leaves the modified versions (\E[1;?H etc) alone.

xterm+modkeys|xterm-style modifier keys,
    kb2=\EOE, kent=\EOM,
    kind=\E[1;2B, kri=\E[1;2A,
    kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S,
    kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf20=\E[19;2~,
    kf21=\E[20;2~, kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~,
    kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S,
    kf29=\E[15;5~, kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~,
    kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~, kf36=\E[24;5~,
    kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R, kf40=\E[1;6S,
    kf41=\E[15;6~, kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~,
    kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~,
    kf49=\E[1;3P, kf50=\E[1;3Q, kf51=\E[1;3R, kf52=\E[1;3S,
    kf53=\E[15;3~, kf54=\E[17;3~, kf55=\E[18;3~, kf56=\E[19;3~,
    kf57=\E[20;3~, kf58=\E[21;3~, kf59=\E[23;3~, kf60=\E[24;3~,
    kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R,
    kDC=\E[3;2~, kDC3=\E[3;3~, kDC4=\E[3;4~, kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~,
    kDN=\E[1;2B, kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B, kDN7=\E[1;7B,
    kEND=\E[1;2F, kEND3=\E[1;3F, kEND4=\E[1;4F, kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F,
    kHOM=\E[1;2H, kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H, kHOM6=\E[1;6H, kHOM7=\E[1;7H,
    kIC=\E[2;2~, kIC3=\E[2;3~, kIC4=\E[2;4~, kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~,
    kLFT=\E[1;2D, kLFT3=\E[1;3D, kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D, kLFT7=\E[1;7D,
    kNXT=\E[6;2~, kNXT3=\E[6;3~, kNXT4=\E[6;4~, kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~,
    kPRV=\E[5;2~, kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~, kPRV6=\E[5;6~, kPRV7=\E[5;7~,
    kRIT=\E[1;2C, kRIT3=\E[1;3C, kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C, kRIT7=\E[1;7C,
    kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A, kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A,

screen-xtermkeys|screen with xterm-style modifier keys,
    use=xterm+modkeys, use=screen,

screen-xtermkeys-256color|screen with xterm keys and 256 colors,
    use=xterm+modkeys, use=screen-256color,

tmux-xtermkeys|tmux with xterm-style modifier keys,
    use=xterm+modkeys, use=tmux,

tmux-xtermkeys-256color|tmux with xterm keys and 256 colors,
    use=xterm+modkeys, use=tmux-256color,

Compile with tic -x tmux-xtermkeys.ti and then set TERM to {tmux,screen}-xtermkeys{,-256color} as appropriate. I included screen for two reasons: First, emacs by default doesn't recognize tmux as a 256-color terminal. Second, some systems' version of the terminfo database is too old to include tmux information (remove these entries to get the file to compile).

It's better to use a screen terminfo entry than an xterm one because tmux used to recommend using screen and its emulation much more closely matches it. One thing you may notice in some circumstances is that text meant to be in standout mode will be in italics - if so, upgrade your terminfo data.

This will also work in other applications that support these keys (i.e. most places that they work now in xterm).

Community
  • 1
  • 1
Random832
  • 37,415
  • 3
  • 44
  • 63
  • Thanks for your suggestions... On both machines, `set -g xterm-keys` does change it so that `M-` outputs the letters "3A" into the buffer (but the cursor doesn't change location and nothing appears in the echo area). `M-` outputs "3B", `M-` is "3C" and `M-` is "3D". I'm about to check your second suggestion. (Please note I've edited my question to include information about the TERM environment variable). – Diagon Dec 05 '15 at 06:09
  • Random832 - Ok, I take your point. I'll keep an eye out, but so far, I'm not having any trouble with `set -g default-terminal "xterm-256color"`, either on my home machine or on the server. In particular, I do not have the problem with text in standout mode being in italics. Thank you for your thorough answer. I'll report back here if/when I need to test out your terminfo entry. (Gives me nightmares of long-ago struggles with termcap files.) – Diagon Dec 06 '15 at 07:04
  • Oh, ok. According to your last link, this issue should be corrected in tmux 2.1, and so using xterm-256color may be a simple temporary fix, even if some minor problems do show up. – Diagon Dec 06 '15 at 07:19
0

Only this worked for me:

in init.el

;; Try to move direction, which is supplied as arg
;; If cannot move that direction, send a tmux command to do appropriate move
(defun windmove-emacs-or-tmux(dir tmux-cmd)
  (interactive)
  (if (ignore-errors (funcall (intern (concat "windmove-" dir))))
      nil                       ;; Moving within emacs
    (shell-command tmux-cmd)) ;; At edges, send command to tmux
  )

;Move between windows with custom keybindings
(global-set-key (kbd "C-k")
        '(lambda () (interactive) (windmove-emacs-or-tmux "up"  "tmux select-pane -U")))
(global-set-key (kbd "C-j")
        '(lambda () (interactive) (windmove-emacs-or-tmux "down"  "tmux select-pane -D")))
(global-set-key (kbd "C-l")
        '(lambda () (interactive) (windmove-emacs-or-tmux "right" "tmux select-pane -R")))
(global-set-key (kbd "C-h")
        '(lambda () (interactive) (windmove-emacs-or-tmux "left"  "tmux select-pane -L")))

in .tmux.conf:

bind -n C-h run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)g?(view|emacs?)(diff)?$' && tmux send-keys C-h) || tmux select-pane -L"
bind -n C-j run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)g?(view|emacs?)(diff)?$' && tmux send-keys C-j) || tmux select-pane -D"
bind -n C-k run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)g?(view|emacs?)(diff)?$' && tmux send-keys C-k) || tmux select-pane -U"
bind -n C-l run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)g?(view|emacs?)(diff)?$' && tmux send-keys C-l) || tmux select-pane -R"
bind -n C-\ run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)g?(view|emacs?)(diff)?$' && tmux send-keys 'C-\\') || tmux select-pane -l"

https://blog.kdheepak.com/emacsclient-and-tmux-split-navigation.html

rofrol
  • 14,438
  • 7
  • 79
  • 77
  • 1
    Well, the point of this question was how to use meta/control/shift-arrow for these commands, rather than redefine them to something else. I'll also add that I have a more involved version of this linked tmux pane <--> emacs window movement. The problem I find is (1) if something slow is happening in emacs, then while I can move to another tmux window, emacs is tied up processing so I remain frozen in the emacs pane. (2) It doesn't work if I sudo emacs. I'll add (3) that I do get confused if I'm in emacs or tmux and swap the commands by mistake. – Diagon Jun 04 '19 at 15:49
  • @Diagon I have this version which also prevent overflowing https://github.com/rofrol/.emacs.d/blob/7f16ff865dc8628a33cab86359773ff226ab1c9e/lisp/rofrol-system.el#L191 https://github.com/rofrol/dotfiles/blob/0f09a13cf13db049e00790e0237edfa92eb66d3f/bin/tmux_navigate.sh https://github.com/rofrol/dotfiles/blob/0f09a13cf13db049e00790e0237edfa92eb66d3f/.tmux.conf#L36 – rofrol Jun 04 '19 at 19:18
  • I like this line: `(ignore-errors (funcall (intern (concat "windmove-" dir)))`. I think I'll use it! :) What do you mean by "prevents overflowing"? – Diagon Jun 04 '19 at 22:30
  • overflow - when you are at top pane, Shift-up will not go to bottom pane. – rofrol Jun 05 '19 at 03:41