Skip to content

Possible regression: tmux silently swallows extended keys #2705

Description

@mohkale

Issue description

My terminal emulator has special extended keys for C-i and C-m distinct from the standard translation of these key sequences to TAB and RET respectively.

Up until recently I used to be able to bind TAB and C-i independently without issue. For example after running tmux bind-key -T prefix / command-prompt -k -p key "list-keys -1N "%%%"". I can do <prefix> / C-i and it shows C-i, whereas <prefix> / TAB showed TAB.

However now C-i is shown as TAB and C-m is shown as RET.

I tried installing an older build (not sure about the specific commit, the version still says next-3.3) and this wasn't an issue there dispite using the same config. I believe this is a regression.

Required information

Please provide the following information:

  • tmux version (tmux -V). tmux next-3.3
  • Platform (uname -sp). Linux unknown
  • $TERM inside and outside of tmux (echo $TERM). st-256color, tmux-24bit
  • Logs from tmux (tmux kill-server; tmux -vv new). older-server-log, master-server-log

Activity

  1. mohkale commented on May 11, 2021

    @mohkale
    Author

    Worth noting other extended keys work fine. C-1 or C-S-a are Ok, it's just C-i, C-m and I imagine some of the other special keys which are implicitly translated to other keys.

  2. nicm commented on May 11, 2021

    @nicm
    Member

    tmux only has one representation for C-i and C-m and they are the same as Tab and Enter.

    The problem if we had two is - if you do bind C-i lsk which do you mean? If someone is using a terminal without extended keys, C-i won't work anymore.

  3. mohkale commented on May 11, 2021

    @mohkale
    Author

    @nicm

    My terminal emulator sends \033[105;5u for C-i and \033[109;5u for C-m. It sends different keys for TAB and RET and I'd like to be able to handle them separately. Which I can on an older tmux version but the one from master seems to implicitly translate \033[105;5u to TAB when it should be to C-i.

  4. nicm commented on May 11, 2021

    @nicm
    Member

    Yes, I know, it is intentional. I'll have to think about what to do, I don't want C-i to stop working for everyone not using extended keys.

  5. mohkale commented on May 11, 2021

    @mohkale
    Author

    @nicm

    I don't want C-i to stop working for everyone not using extended keys.

    Fair enough, but the issue I have is in emacs I've bound C-i seperate from TAB and tmux seems to send TAB in both cases. I can understand tmux internally treating C-i as TAB but when sending to a pane I'd prefer it sent the same input that was sent to tmux instead of deciding to send what it thinks the input was.

    Admittedly I'm not very experienced in the domain of terminal emulators. There might be some special mode or sequence emacs has to send to get this working, not sure whether this is an application problem or a tmux one :/.

  6. mohkale commented on May 11, 2021

    @mohkale
    Author

    @nicm

    Actually if you enable extended keys shouldn't you expect C-i to stop working as TAB. You're sending different sequences so expecting the same behaviour seems odd.

  7. nicm commented on May 11, 2021

    @nicm
    Member

    emacs will need to send the sequence to enable extended keys or you will need to set extended-keys to always.

    But at the moment C-i and Tab will be the same no matter what.

  8. nicm commented on May 11, 2021

    @nicm
    Member

    If someone does bind C-i lsk in .tmux.conf but their C-i key actually sends Tab then if tmux treats them differently C-i will not work.

  9. mohkale commented on May 11, 2021

    @mohkale
    Author

    emacs will need to send the sequence to enable extended keys

    How do I check whether it's done this or not, other extended keys (eg. C-1) work fine so it might've.

    you will need to set extended-keys to always.

    I did try that before opening the issue, didn't have any noticable difference.

    But at the moment C-i and Tab will be the same no matter what.

    Yep. That's my issue 😋. Would you be open to distinguishing them through a terminfo extension or something to that affect.

  10. nicm commented on May 11, 2021

    @nicm
    Member

    If they are working then emacs must do it.

    Right but it is not as easy as just knowing it should happen.

    I think tmux will need to store C-i and Tab as separate key codes and then do some sort of "try this key also" lookup if extended keys is set to off.

    So when tmux comes to lookup Tab in the key tables it first tries it as-is and if that is not found it tries it as C-i as well if extended-keys is off.

  11. nicm commented on May 14, 2021

    @nicm
    Member

    We currently (deliberately) only support modifyOtherKeys mode 1 which does not alter Tab/C-i.

    It would be nice to support modifyOtherKeys mode 2 also but it changes a lot more keys as well. So the easier stuff is:


    1. tmux would have to represent the keys differently internally, I am not sure whether it is better to replace C-i with KEYC_CTRL|'i' and leave Tab as \011 or to replace Tab with KEYC_TAB and leave C-i as \011. Similarly for C-a, does it become KEYC_CTRL|'a' or remain \001? It seems more consistent to do the former, but probably less disruptive to do the latter.

    2. All the internal use of keys would have to change to the new mapping (key-string.c, status.c, mode-tree.c, window-*.c).

    3. Incoming keys (tty-keys.c) would need to map the keys correctly, and Backspace would need to be dealt with.

    4. When writing keys to panes which have not sent the escape sequence or have requested mode 1, keys would need to be mapped, so KEYC_CTRL|'i' sends \011, KEYC_CTRL|'a' sends \001 and so on. We already do this to map, for example, C-S-i to C-i - see input-keys.c:486.


    The problems come with key bindings:

    1. If someone binds C-i, C-I or Tab in .tmux.conf at the moment, they are the same. Likewise, C-S-i, C-S-I or S-Tab are all S-Tab. We do not want to break this, and I am not sure the best way to do it. Perhaps we add a separate modifier for "mode 2 ctrl key" so C-i would have to be bound as E-i or something, if you bind C-i you end up with Tab as before. Not very intuitive however.

    2. modifyOtherKeys = 2 terminals send C-S-A (27;6;65) for C-S-a. But we need C-A and C-a to both be C-a. This is not so big a problem I think because I don't know of any terminals that actually send C-S-a (27;6;97), so it is probably OK just to force all C-A to C-a on input and map C-S-a to C-S-A on output for mode 2 panes.

  12. mohkale commented on Jun 14, 2021

    @mohkale
    Author

    @nicm

    Have you had a chance to think more on modifyOtherKeys mode 2?

    I just did a system upgrade which accidentally upgraded tmux as well and now I'm gonna have to revert back to make sure all my keybindings still work 😁.

    EDIT:

    I couldn't seem to get the earlier version of tmux to build (strange makefile shenanigans). In the end I ended up commenting out the following block and my extended-keys started working again. This is a stop-gap fix and almost certainly will break something somewhere else but if any-one else wants a quick and dirty solution here it is:

    diff -u --label /home/mohkale/.local/temp/20210614.225927/tty-keys.c --label \#\<buffer\ tty-keys.c\> /home/mohkale/.local/temp/20210614.225927/tty-keys.c /tmp/buffer-content-qkwMFp
    --- /home/mohkale/.local/temp/20210614.225927/tty-keys.c
    +++ #<buffer tty-keys.c>
    @@ -957,25 +957,25 @@
     	 * Don't allow both KEYC_CTRL and as an implied modifier. Also convert
     	 * C-X into C-x and so on.
     	 */
    -	if (nkey & KEYC_CTRL) {
    -		onlykey = (nkey & KEYC_MASK_KEY);
    -		if (onlykey < 32 &&
    -		    onlykey != 9 &&
    -		    onlykey != 13 &&
    -		    onlykey != 27)
    -			/* nothing */;
    -		else if (onlykey >= 97 && onlykey <= 122)
    -			onlykey -= 96;
    -		else if (onlykey >= 64 && onlykey <= 95)
    -			onlykey -= 64;
    -		else if (onlykey == 32)
    -			onlykey = 0;
    -		else if (onlykey == 63)
    -			onlykey = 127;
    -		else
    -			onlykey |= KEYC_CTRL;
    -		nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL);
    -	}
    +	/* if (nkey & KEYC_CTRL) { */
    +	/* 	onlykey = (nkey & KEYC_MASK_KEY); */
    +	/* 	if (onlykey < 32 && */
    +	/* 	    onlykey != 9 && */
    +	/* 	    onlykey != 13 && */
    +	/* 	    onlykey != 27) */
    +	/* 		/\* nothing *\/; */
    +	/* 	else if (onlykey >= 97 && onlykey <= 122) */
    +	/* 		onlykey -= 96; */
    +	/* 	else if (onlykey >= 64 && onlykey <= 95) */
    +	/* 		onlykey -= 64; */
    +	/* 	else if (onlykey == 32) */
    +	/* 		onlykey = 0; */
    +	/* 	else if (onlykey == 63) */
    +	/* 		onlykey = 127; */
    +	/* 	else */
    +	/* 		onlykey |= KEYC_CTRL; */
    +	/* 	nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL); */
    +	/* } */
     
     	if (log_get_level() != 0) {
     		log_debug("%s: extended key %.*s is %llx (%s)", c->name,
    
    Diff finished.  Tue Jun 15 00:30:13 2021

    In the mean-time I'll try to get started on the suggestions by nicm (at least the easy ones).

  13. nicm commented on Jun 15, 2021

    @nicm
    Member

    I started looking at it but it is substantial work and I don't have time to do it at the moment.

  14. liaden commented on Sep 17, 2021

    @liaden

    Just a heads up but I ran into what I assume is the same thing with and when going from 3.1 to 3.2a.

  15. added a commit that references this issue on Dec 8, 2021
  16. 25 remaining items

  17. LinuxIsCool commented on Feb 5, 2024

    @LinuxIsCool

    Got it.

    Downgrade to 3.1c and add the following to alacritty.yml:

    key_bindings:
        - { key: I, mods: Control, chars: "\x1b[105;6u"
    
  18. realSaltyFish commented on Mar 6, 2024

    @realSaltyFish

    @mohkale Thanks for the pointer to the related snippet. I revisited this issue today because I can no longer ignore the inconvenience of not being able to yank in vi mode in version 3.1_c. Could someone help me check my understanding:

    This function tty_keys_extended_key essentially handles CSI u sequences. Applications that do support CSI u sequences will ask about the availability of support in the terminal emulator, and the terminal emulator (I am using kitty) will start sending these sequences instead of legacy keycodes.

    Normally without tmux this should work fine, but tmux intercepts the CSI u sequences and translates those that correspond to Ctrl-keys back into their original forms. IMO this is unnecessary and incorrect behavior. If the terminal emulator does not support CSI u sequences, it would not have sent those in the first place so this function is never invoked. I think tmux should honor the terminal emulator's intention and not interfere with applications that explicitly ask for CSI u support.

    I have also confirmed that removing this translation does NOT break legacy terminal emulators. I recompiled tmux without the following lines:

    		else if (onlykey >= 97 && onlykey <= 122)
    			onlykey -= 96;

    If I configure kitty to send \x1b[105;5u for ctrl+i, ^[[105;5u is printed correctly in cat when I press ctrl+i. Otherwise (if I don't specify this keymap in kitty config) it delivers Tab.

    I think it is fully safe to remove these lines, and all Neovim/Emacs/kakoune/etc. users will be happy then.

    @nicm Please point out if I missed anything. PR is on the way. I still need to figure out what other lines nearby are doing though. Pointers are welcomed.

  19. realSaltyFish commented on Mar 7, 2024

    @realSaltyFish

    Found some references:

    I plan to rework this function to match the specification I found. Let me know if it doesn't make sense or needs more discussion.

  20. stevenxxiu commented on Mar 8, 2024

    @stevenxxiu

    See also Comprehensive keyboard handling in terminals - kitty. It's an improved Fix Terminals - Please that's used by many programs.

  21. tummetott commented on Mar 8, 2024

    @tummetott

    See also Comprehensive keyboard handling in terminals - kitty. It's an improved Fix Terminals - Please that's used by many programs.

    Yess I second this. If tmux would support kitty's keyboard protocol all problems would be solved as it's superior and backward compatible with fixterm CSI u sequences

  22. edte commented on Mar 12, 2024

    @edte

    @mohkale Thanks for the pointer to the related snippet. I revisited this issue today because I can no longer ignore the inconvenience of not being able to yank in vi mode in version 3.1_c. Could someone help me check my understanding:

    This function tty_keys_extended_key essentially handles CSI u sequences. Applications that do support CSI u sequences will ask about the availability of support in the terminal emulator, and the terminal emulator (I am using kitty) will start sending these sequences instead of legacy keycodes.

    Normally without tmux this should work fine, but tmux intercepts the CSI u sequences and translates those that correspond to Ctrl-keys back into their original forms. IMO this is unnecessary and incorrect behavior. If the terminal emulator does not support CSI u sequences, it would not have sent those in the first place so this function is never invoked. I think tmux should honor the terminal emulator's intention and not interfere with applications that explicitly ask for CSI u support.

    I have also confirmed that removing this translation does NOT break legacy terminal emulators. I recompiled tmux without the following lines:

    		else if (onlykey >= 97 && onlykey <= 122)
    			onlykey -= 96;

    If I configure kitty to send \x1b[105;5u for ctrl+i, ^[[105;5u is printed correctly in cat when I press ctrl+i. Otherwise (if I don't specify this keymap in kitty config) it delivers Tab.

    I think it is fully safe to remove these lines, and all Neovim/Emacs/kakoune/etc. users will be happy then.

    @nicm Please point out if I missed anything. PR is on the way. I still need to figure out what other lines nearby are doing though. Pointers are welcomed.

    I compiled your fork and configured it in kitty map ctrl+i send_text all \x1b[105;5u But after restarting tmux, ctrl+i will still be recognized as tab.

  23. sotte commented on Jun 7, 2024

    @sotte

    For completeness I'm cross linking this (closed) issue #3335 which proposes to implement the kitty keyboard protocol. This would make it easier to handle/distinguish key sequences like ctrl-i and tab.

  24. added a commit that references this issue on Jul 28, 2024
  25. added a commit that references this issue on Sep 12, 2024
  26. nicm commented on Nov 22, 2024

    @nicm
    Member

    Mode 2 is now supported and mode 1 more fully as of tmux 3.5a, although I would probably use master since there have been a few fixes.

  27. github-actions commented on Dec 23, 2024

    @github-actions

    This issue has been automatically locked since there has not been any recent activity after it was closed.

  28. locked as resolved and limited conversation to collaborators on Dec 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions