Terminal: Ctrl+Tab toggle between last two windows like Alt+Tab

Created on 24 May 2019  路  14Comments  路  Source: microsoft/terminal

Ctrl+Tab allows you to move forward through open tabs. I'd like an option that works like Alt+Tab so I can just press Ctrl+Tab once to go to a previous tab and Ctrl+Tab a second time to go back to the current tab.

Area-Settings Area-User Interface Help Wanted Issue-Feature Product-Terminal Resolution-Fix-Committed

Most helpful comment

I think the OP wants most-recent-used (MRU) behaviour. Therefore having Ctrl+Shift+Tab take you to previous does not meet this requirement as it is still _tab order_, not MRU order.

The key binding at the moment is:

            {
                "command" : "nextTab",
                "keys" : 
                [
                    "ctrl+tab"
                ]
            }

It would be great if an mruTab command could be added so that people could bind it to Ctrl+Tab even if it isn't the default behaviour.

One thing worth mentioning is that Alt+Tab has a subtle but important behaviour: when you hold down Alt and then hit Tab repeatedly, it cycles through the MRU list _until you release Alt_ at which point the window switch is made and the MRU list updated. This is also evidenced in apps that support Ctrl+Tab with MRU behaviour, eg. the excellent ConEmu...

All 14 comments

I'm pretty sure Ctrl+Shift+tab will take you back to the previous tab.

Now, cycling through the tabs in the order that they were last activated, as opposed to linearly through the list of tabs is certainly an interesting idea. It'd definitely have to be a separate setting from the current behavior, since some people are going to like it the current way, while others will like it the way you described.

I think the OP wants most-recent-used (MRU) behaviour. Therefore having Ctrl+Shift+Tab take you to previous does not meet this requirement as it is still _tab order_, not MRU order.

The key binding at the moment is:

            {
                "command" : "nextTab",
                "keys" : 
                [
                    "ctrl+tab"
                ]
            }

It would be great if an mruTab command could be added so that people could bind it to Ctrl+Tab even if it isn't the default behaviour.

One thing worth mentioning is that Alt+Tab has a subtle but important behaviour: when you hold down Alt and then hit Tab repeatedly, it cycles through the MRU list _until you release Alt_ at which point the window switch is made and the MRU list updated. This is also evidenced in apps that support Ctrl+Tab with MRU behaviour, eg. the excellent ConEmu...

I would like to see this one as well. Switching between the actual and the last viewed tab with the same shorcut is a big time saver. This should be a separate setting though. preserving the old behavior of the nextTab and prevTab, something like this:
{ "command" : "nextTab", "keys" : [ "ctrl+tab" ] }, { "command" : "prevTab", "keys" : [ "ctrl+shift+tab" ] }, { "command" : "LastTab", "keys" : [ "shift+tab" ] },

I think MRU tab switching for both Ctrl+Tab and Ctrl+Shift+Tab (the latter cycling the MRU stack in reverse order) should be the default behavior because

  • it's been the default for multi-document interfaces (tabbed windows) in Windows for a long time (see, e.g., Visual Studio/SQL Server Management Studio, Notepad++, or MFC-based applications that use MDI),
  • it's symmetric with Windows' own Alt+Tab, and
  • it's "better" user experience because it leverages short-term memory/work context.

Here are some examples for the last item:

  • You are working in a terminal tab and need to look something up on another tab, then switch back.
  • You need to switch between two tabs a lot because of copying different items from one to the other or because of comparing some text.

To me, there doesn't seem to be a use case where left-to-right (rather than MRU) is the "better" behavior?

BTW, MRU should also be the default when closing tabs: Have a number of tabs open. From the first one, open a new tab. Close it again. Where are you now? Not where you were before. (This argument was borrowed from https://bugs.chromium.org/p/chromium/issues/detail?id=5569#c79.)

For what it's worth, I spent a good 5 hours or so trying to make this happen so I could issue a PR. It is HARD, at least for someone who hasn't really done C++ since MFC and OLE were all the rage with the cool kids. @jugglingcats last note is the real sticking point.

Easy parts:

  • Add NextTabMru and PrevTabMru bindings and such across the board.
  • Create a "local" MRU stack for the tab indexes

Moderate:

  • Add event handler for TermControl PreviewKeyUp event
  • Modify IKeyBindings to add a NotifyModifierReleased method so that this event can report this back to AppKeyBindings

Impossible for lil' ol' me (without a hideous hack):

  • Differentiate between a "click" tab change and a keyboard shortcut tab change in the TerminalPage OnTabSelectionChanged handler so that I can determine when to move the selected tab to the top of the MRU stack (should ONLY happen on a click or after control is released).
  • Figure out a non-hack, architecturally consistent way to "share" the MRU stack between TerminalPage and AppKeyBindings

Really, this should all be done such that an MRU change doesn't actually change the selected tab at all until you release the control key (or whatever modifiers you've defined). This would make it trivial to manage the stack. BUT it would require a pop-up control (listbox, listview, etc.) to show and cycle through open tabs. Same as VS and VS Code (and Firefox...only browser I can use since it supports MRU tab switching). And I'd give it a go personally, but adding GUI elements in C++ Win UI is way out of my comfort zone.

I'm 100% with @fschmied. MRU tab switching should be the default. Period. SO much more intuitive and consistent from an HCI perspective. Not sure when folks started to move away from it and whether it was just because it is by far "easier" to just cycle left to right. But it is a very bad trend, IMO.

Hey @ptyork, thanks for looking into this!

Regarding sharing state between Page and AppKeyBindings, this might help: Bindings should architecturally only emit events to which page can subscribe. The event callbacks are in AppActionHandlers, which is actually a poorly-named file that contains all of the event handlers in _TerminalPage_.

It's our bad that TermControl has to know about key bindings at all. Sorry! I actually thought we were tracking this in a workitem somewhere, so that's homework for me. :smile:

Just adding a comment here that this NEEDS to happen. MRU tab-switching order is the standard, and there are DECADES of muscle-memory associated with them. The only application that doesn't do this is Chrome, and it's why I hate using Chrome (and now EDGE). EVERY other tabbed UI in the universe does this the right way... MRU tab switching. If you have more than two tabs open, the "just switch to the left/right" tab switching is utterly annoying and useless, and introduces too high of a cognitive load to try and remember where you are, where you want to go, and whether you should use Ctrl-Tab or Shift-Ctrl-Tab to get there. It's just horrible usability, and I curse Chrome every day for not implementing at least the OPTION of having MRU tab switching (as IE did, and as FireFox does). It should be verboten to introduce any kind of tabbed UI without this option. This should be a high-priority addition. There are tons of examples of how this should work already, so all the usecases and edgecases should be taken care of (Visual Studio, SQL Server Management studio, Notepad++, FireFox (with the option turned on in settings), IE11 (with the option turned on in settings), Alt-Tab behavior in Windows itself, etc.

:tada:This issue was addressed in #7952, which has now been successfully released as Windows Terminal v1.4.3141.0.:tada:

Handy links:

:tada:This issue was addressed in #7952, which has now been successfully released as Windows Terminal Preview v1.5.3142.0.:tada:

Handy links:

How do I return to Pre-MRU behavior? I somehow can't find it in the documentation.

How do I return to Pre-MRU behavior? I somehow can't find it in the documentation.

@nsballmann - in 1.5 Preview you can set "tabSwitcherMode" in global settings.
The available values are "mru", "inOrder", "disabled". I guess you are looking for "inOrder"

In 1.4 (as @kwburnett suggested below) you can fully disable the tab switcher with "useTabSwitcher" set to false, which will also fallback to the "inOrder" behavior, but you won't see tab switching UI.

How do I return to Pre-MRU behavior? I somehow can't find it in the documentation.

@nsballmann - you can set "tabSwitcherMode" in global settings.
The available values are "mru", "inOrder", "disabled". I guess you are looking for "inOrder"

This didn't work for me. However, setting "useTabSwitcher" to false in the global settings did the trick.

How do I return to Pre-MRU behavior? I somehow can't find it in the documentation.

@nsballmann - you can set "tabSwitcherMode" in global settings.
The available values are "mru", "inOrder", "disabled". I guess you are looking for "inOrder"

This didn't work for me. However, setting "useTabSwitcher" to false in the global settings did the trick.

@kwburnett - I was addressing 1.5 Preview. In 1.4 you can turn off tab switcher completely (the way you did with "useTabSwitcher"), but it will hide the tab switcher UI as well.

Currently I'm on 1.4. I just put both into my config, so it will be easy for me, when 1.5 goes from preview to release.

{
  "useTabSwitcher": false,
  "tabSwitcherMode": "inOrder"
}

Thank you both very much, @Don-Vito and @kwburnett .

Was this page helpful?
0 / 5 - 0 ratings

Related issues

carlos-zamora picture carlos-zamora  路  3Comments

DieselMeister picture DieselMeister  路  3Comments

mrmlnc picture mrmlnc  路  3Comments

NickITGuy picture NickITGuy  路  3Comments

dev-logan picture dev-logan  路  3Comments