Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Overriding keybindings is unintuitive and difficult #110

Closed
adzenith opened this issue Jan 27, 2016 · 37 comments
Closed

Overriding keybindings is unintuitive and difficult #110

adzenith opened this issue Jan 27, 2016 · 37 comments
Labels

Comments

@adzenith
Copy link

I want to bind cmd-shift-d to atomic-rtags:follow, but it's stuck as editor:duplicate-lines. The former is defined as atom-workspace atom-text-editor, whereas the latter is defined as atom-workspace atom-text-editor:not([mini]). Why does my custom keybinding not override the built-in one? (Yes, I've discovered that the technical answer is "because its context is more specific".) I feel like this should be easy for me to remedy by myself without reading through issues on Github.

The only solution of which I am aware is to track down every usage of the offending shortcut by using the keybinding resolver, click on it to open the file it's in, search through that file to find the keybinding (because the link doesn't take you to the relevant line), copy and paste its context into my user keymap, and bind the key to !unset. Then, if ever any package rebinds this shortcut, I also have to remember and rerun these steps for that shortcut as well. Is this the correct approach? Or is there some simple easy way that I just can't figure out?

Thanks!

@adzenith
Copy link
Author

I can't actually get unset! to work. The keybinding resolver shows three black check marks (the first one corresponding to the unset! command). For other commands, it shows one green check mark and grey Xes for commands that weren't run. I'm not sure what's going on.

I ended up overriding atom-workspace atom-text-editor:not([mini]), which appears to work.

@lee-dohm
Copy link
Contributor

We know that the system is confusing (see #49, #33, atom/atom#6718, among others). We continue to discuss ideas of how to make the keybinding system more approachable while maintaining the flexibility and power of the current system.

unset! is only useful when you want to disable a key completely. When you want a key to be bound to a different command than the default, it is unnecessary to use unset!.

If a keybinding is winning out over your desired one, such as editor:duplicate-lines in your example above, this is what you should do:

  1. Find the selector for the winning keybinding
  2. Add the selector to your keymap.cson if it does not already exist there
  3. Add your desired keybinding under that selector in step 2

So, continuing the example, you need to add this to your keymap.cson:

'atom-workspace atom-text-editor:not([mini])':
  'cmd-shift-d': 'atomic-rtags:follow'

Keep in mind that you should only have one instance of each selector in your keymap.cson because if you duplicate selectors, only the last one will be read by the system.

@dragonxlwang
Copy link

unset! is only useful when you want to disable a key completely. When you want a key to be bound to a different command than the default, it is unnecessary to use unset!.

Hi @lee-dohm , following your instruction, I found that in preference panel -> keybinding, for the same key and selector, I can see the same key mapped to two entries. Is that okay as long as the user (I) defined one wins over the plugin/system one?

image

@lee-dohm
Copy link
Contributor

@dragonxlwang Yes, it is. For example, here's the list of what is mapped to Tab on my installation of Atom:

screen shot 2016-03-16 at 9 53 00 pm

We designed the keybinding system so that one could use the same key (or key combination) in different areas of the application or in the same area of the application for different things.

@dragonxlwang
Copy link

thanks!

But what do you mean by

in the same area of the application for different things.

?? Shouldn't the behavior in one selector for the same key to be deterministic?

@lee-dohm
Copy link
Contributor

lee-dohm commented Mar 17, 2016

While it is not quite deterministic, it is cooperative. In the keybinding documentation it covers how multiple keybindings can be bound to the same key and how they cooperate so that if the first key's job isn't applicable, it defers to the next one. Notice that I have, for the exact same selector (in red), three different packages (in blue, green, and orange) mapping four different commands to Tab:

comparison

@dragonxlwang
Copy link

that makes lots senses. Thanks for explaining! just want to be sure, while reading this section in the link:

Specificity and Cascade Order

As is the case with CSS applying styles, when multiple bindings match for a single element, the conflict is resolved by choosing the most specific selector. If two matching selectors have the same specificity, the binding for the selector appearing later in the cascade takes precedence.

Does it ensure that user defined key always take more priority than others?

@lee-dohm
Copy link
Contributor

Does it ensure that user defined key always take more priority than others?

No, CSS specificity states that all things being equal, the last one to be loaded wins. But there are plenty of things that can cause a built-in keybinding to override a user-specified keybinding. One of our long-standing community members, @mark-hahn, has been recommending this tutorial for learning about specificity in CSS:

http://specificity.keegan.st/

@dragonxlwang
Copy link

No, CSS specificity states that all things being equal, the last one to be loaded wins.

But when is the .atom/keymap.cson loaded? I hope it would be loaded last. It seems so...

@mark-hahn
Copy link

I hope it would be loaded last.

Yes it is, but that doesn't override the specificity rules. It is treated exactly as CSS rules are treated in a web page.

@dragonxlwang
Copy link

Thanks @mark-hahn

@courthead
Copy link

courthead commented May 1, 2016

The keybinding system has been confusing an unintuitive for me since the day I installed Atom years ago, and for everyone I've introduced to Atom as well. It's extremely frustrating how difficult it is to accomplish the simplest and most common of tasks: changing a key from one behavior to another.

This morning (on Atom 1.7.3) I wanted to change ctrl-tab from pane:show-next-recently-used-item to pane:show-next-item. By default, the selector is set to body, so one would think this is all I need to add to my keymap:

'body':
  'ctrl-tab': 'pane:show-next-item'
  'ctrl-shift-tab': 'pane:show-previous-item'

But nope, this has the bewildering and completely undesirable result of running both my keybinding and the default keybinding at the same time:

overridden-keybinding

Even though the keybinding I defined is highlighted in green, both it AND the grey keybinding are running simultaneously when I press ctrl-tab. Why? No amount of reading the docs makes this behavior intuitive. It's completely broken.

In order to finally get this simple change working, I had to not only unset the current keybindings in their selector, but then come up with a different selector to set my keybindings:

'body':
  'ctrl-tab': 'unset!'
  'ctrl-shift-tab': 'unset!'

'.platform-darwin':
  'ctrl-tab': 'pane:show-next-item'
  'ctrl-shift-tab': 'pane:show-previous-item'

I love Atom, but this keybinding nonsense is endlessly frustrating. Even if this is just a one-off bug, or a mistake on my part, I have experiences like every single time I try to change keybindings... which I have to try more often than I should, since updates to Atom frequently make changes to the default keybindings I've gotten used to, forcing me to override them.

@winstliu
Copy link
Contributor

winstliu commented May 1, 2016

@courthead your issue is because the MRU keybinding is actually ctrl-tab ^ctrl, which needs to be unset separately. Here's an example of how you should change your keybindings to revert to the original left->right tab switching: atom/atom#11035 (comment)

@courthead
Copy link

courthead commented May 1, 2016

Thanks for the info. Turns out you have to use unset! not abort!, though, so this is the correct code: atom/atom#11035 (comment)

Anyway, this is just another example of keybindings being extremely difficult to use. What is ^ctrl? Why do I have to specify ^ctrl in my custom keymap but it doesn't appear when the key is pressed in the Key Binding Resolver, nor in the keybindings table in the settings, nor when I copy the keybinding from settings? It's almost like it's deliberately intended to mislead and confuse.

@winstliu
Copy link
Contributor

winstliu commented May 1, 2016

The missing ^ctrl is most likely a bug. What the ^ syntax means is that the command is not executed until the key following the ^ is released. So ctrl-tab ^ctrl would keep cycling through tabs until ctrl is released. See #113 for the PR that added this.

@derwaldgeist
Copy link

+1 The current system is more than confusing, even for experienced CSS developers like me. The simple reason is that you have to know exactly what the most specific rule is in order to override it. I know know that there's a key resolver, but this wasn't intuitive either. In most other editors, you just have a GUI where you can set key bindings to your liking.

@thiagocmoraes
Copy link

thiagocmoraes commented Jun 3, 2016

I was trying to do exactly the change @courthead wanted and I got as far as getting the code below done:

'body':
  'ctrl-tab': 'pane:show-next-item'
  'ctrl-shift-tab': 'pane:show-previous-item'

Figuring out that a Key Resolver existed show me that my rules wasn't being executed, but I had to get to issue tracker to find out what I wanted and even after that, I was only able to do it because someone wanted exactly the same thing.

Googling returns multiple issues and no place seems authoritative about how to learn about this at all. Can we at least think of providing some commented examples in keymap.cson by default?

That would alleviate the pain.

@carlgao
Copy link

carlgao commented Jun 4, 2016

I was trying to do the exact same thing as @courthead and @thiagocmoraes, and after an hour finally figured out that I needed to put:

'body':
  'ctrl-tab': 'unset!'
  'ctrl-shift-tab': 'unset!'

'.platform-darwin':
  'ctrl-tab': 'pane:show-next-item'
  'ctrl-shift-tab': 'pane:show-previous-item'

BEFORE


'atom-text-editor.vim-mode:not(.insert-mode)':
  'g u': ''

'atom-text-editor.vim-mode.visual-mode':
  'u': ''

'atom-text-editor':
  'cmd-shift-D': ''

in keymap.cson. It actually turns out that anything I put after the 'atom-text-editor' rules gets ignored, I think. Why?? WHY?? I can't believe spent a whole hour on this T_T

@belgacea
Copy link

belgacea commented Aug 1, 2016

+1000

@wtgee
Copy link

wtgee commented Aug 2, 2016

👍 It is very difficult to do even the most basic keybinding overrides. I shouldn't even have to be looking this up and I still can't actually even figure it out.

@crearo
Copy link

crearo commented Aug 14, 2016

I moved to atom from ST2. I've been stuck at trying to change my key binding for ctrl-up and ctrl-down (scroll up/down line by line) for the past hour, and still can't get it to work! Is there someone who's been able to change the keybinding for this successfully?

@pdf
Copy link

pdf commented Aug 26, 2016

The keybinding story sucks really hard. Having tried numerous combinations, unset! does not appear to work reliably at all.

Not being able to copy-paste from the keybinding resolver pop-up doesn't help.

Please at least give us !important or similar, or just give user keymaps precedence so we don't have to wade through this horrific mess. It's currently vastly more painful than it needs to be.

@nathansobo
Copy link
Contributor

Hey, I hear you guys. I'm currently focused on other pain points but this is on my radar to improve. I originally designed the selector based system in an attempt to make things flexible in the face of different packages written by different people interacting in the same DOM. It may be too flexible.

It's going to take some thinking about how to extend it with a better user interface or replace it in a way that preserves backward compatibility. In the meantime, sorry for the sucky experience. I don't know what else to say right now other than I care but can't drop everything this second to fix it.

If people want to start discussing proposals for how this should ideally work, I'm all ears.

@mark-hahn
Copy link

The worst part is the bug in cson that it doesn't throw an error when you
have multiple matching properties. This constantly causes confusion.
Maybe atom could check for this?

On Fri, Aug 26, 2016 at 2:02 PM, Nathan Sobo [email protected]
wrote:

Hey, I hear you guys. I'm currently focused on other pain points but this
is on my radar to improve. I originally designed the selector based system
in an attempt to make things flexible in the face of different packages
written by different people interacting in the same DOM. It may be too
flexible.

It's going to take some thinking about how to extend it with a better user
interface or replace it in a way that preserves backward compatibility. In
the meantime, sorry for the sucky experience. I don't know what else to say
right now other than I care but can't drop everything this second to fix it.

If people want to start discussing proposals for how this should ideally
work, I'm all ears.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#110 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAxhv-OunhZovvQDSJvJO_b5IAlMaeSUks5qj1RigaJpZM4HN3lb
.

@courthead
Copy link

Thanks for replying @nathansobo! I think the system needs to be primarily focused on the 99% use-case: overriding some existing keybinding with a new one. That should be easy, intuitive, and reliable for anyone to do, without requiring users to:

  • understand Atom's selectors and/or know them by heart
  • understand "unset!", "abort!", etc
  • guess and check
  • browse source code of any kind
  • wade through pages of GitHub issues

Ideally, it would be as simple as key combo --> desired action and that's it. Yes, there are edge cases where users want multiple actions to fire with one key combo, or a combo to do different things in different places, etc. Those are rare exceptions to the rule, however. Only those particular edge cases should require any special knowledge, or research, or code/config.

@nathansobo
Copy link
Contributor

We're taking the advice of some people on this thread in atom/atom#12760, which always gives precedence to user bindings regardless of selector specificity and displays errors when a keymap contains duplicate keys.

I'm hoping that these changes make unset! a lot easier to use in the rare cases it's required. Ultimately, a graphical UI for designing bindings may be the ultimate solution, but I'd like to see how people feel after we release these changes in 1.12.0. If it's still a problem, we can reopen this issue.

@lee-dohm
Copy link
Contributor

@JD719 your comment was deleted as a violation of the Atom Code of Conduct as it is insulting or derogatory. You may consider this an official warning.

@edmundlaugasson
Copy link

edmundlaugasson commented Dec 27, 2016

Does not work for me

I have to admit that neither:
'unset!': 'editor:select-line'
or
'': 'editor:select-line'
... does not work...

When saving or just opening Atom, it continuously announces:

Failed to load ~/.atom/keymap.json
duplicate key ...

... as I am trying to apply same disabling scheme for more than one keybinding. Looks like there is no solution or workaround for that. I'm stuck...
Looks very awesome app but yes, keybinding does not work (yet).

Couple of ideas:

  • add a choice Disable all built-in keybindings in upper area of that Settings site - then anyone who would like to disable them, could do that
  • changing keybinding should be possible directly in GUI, e.g. Settings->Keybindings and just by clicking with mouse on current keybinding will ask enter new one and applies it automatically by replacing old ones. New keybinding is captured automatically. For those who would like to type manually - that way should also remain but directly in that GUI. Editing cryptic config file is for non-programmers a bit overkill.
  • Somewhere upper area of that settings site should contain a key legend - what abbreviations to use for keybindings and what character connects them: dash, plus or any other one. An example as small text in that upper area of how to properly apply keybinding would be good idea.
  • To add more keybindings for one item, e.g. hold CTRL while clicking current one to replace or something.
  • Just every keybinding row should have Restore default choice or make possible to select row and click the button Restore default in upper part of that site. Also Restore all keybindings to default option would be useful in order to restore all keybindings to defaults. There could be also Restore selected keybindings to defaults option. Also offering keybindings restoring by selector, source could be useful. There could be also a checkbox e.g. Make backup of current keybindings setting file and this could be selected by default. Then also Restore keybindings from backup would be appreciated choice and choosing manually a keybinding file would be also appreciated.
  • Make possible to remove specific keybinding from all current places. E.g. if to type any keybinding into search field and it shows that it is assigned in more than one places then there would be useful to have a button e.g. Remove searched keybinding from all current places and allow to leave one or more selected one of them, it means it will remove all but not these ones which are selected. If none are selected then it removes all. Also quick restore button would be useful to restore recently removed keybinding(s).
  • Reload keybindings button in upper area of that settings site would be useful in order to understand whether new keybindings are reloaded or not. Currently I have to close the app in order to be sure the new keybindings are reloaded.
  • Try to map already known keybindings, e.g. F9 to view/hide tree; CTRL+H for find/replace etc.
  • Still there is a question - how to open multiple files from same project/folder... Even from different project there is not possible to open multiple files - all the time the same file is opening in same tab... This looks not logical to handle it...

Settings should be saved automatically and could be fine-tuned by hand like currently (v1.12.7) - this edit your keymap file option should also remain for those who are familiar with it. Others who are not familiar, could be in one day when learning what program has been written when changing keybindings via GUI.

@Zerim
Copy link

Zerim commented Jan 12, 2017

FYI I think changing user keymap settings as the equivalent of an !important is a positive change.

However, for me the not loading of duplicate keys was a breaking change. The error also does not specify the offending line member, which makes it very difficult to track down what the actual error is (I was using that key in quite a few different selectors).

Furthermore the docs at a glance lead you to believe that 'overloading keybindings' is something that is supported, and only in the fine print does indicate that Atom does support executing two commands from a single keybinding (though there still seem to be contradictory statements).

About an hour spent debugging until stumbling across this issue and reading through the intents of the change.

Thank you for the great editor, just sharing my poor experiences with this. Having the error show line number, or even link to the PR, an item in the change log or this issue would have been very helpful.

@winstliu
Copy link
Contributor

winstliu commented Jan 13, 2017

However, for me the not loading of duplicate keys was a breaking change.

Atom never loaded duplicate keys* (the last one would win priority). It just wasn't obvious until the error notification was added.

If you could please open an issue on atom/atom asking for the line number to be added to the notification, that would be great.

* Assuming that you meant a key as in atom-text-editor and not an actual keybinding.

@dreftymac
Copy link

Fix broken link to overriding keybindings

@nathansobo
Copy link
Contributor

Thanks! Fixed in the original.

@phoenixeliot
Copy link

Had the same issue as @courthead, and took a solid 20 minutes to dig enough to find that I needed to also unset the ^ctrl part. That part in particular needs some better surfacing of why one command is happening instead of another (especially since that particular customization of ctrl-tab seems to be pretty common).

@lee-dohm
Copy link
Contributor

lee-dohm commented Oct 4, 2017

We have another method of choosing the behavior of Ctrl+Tab that doesn't require any knowledge of customizing keybindings seen in the Atom FAQ here:

https://discuss.atom.io/t/i-want-ctrl-tab-to-work-like-it-used-to-how-do-i-do-that/28639

@vibrunazo
Copy link

I think the best solution for this problem would be to simply change the default snippet for "key" to something else that takes higher priority over all native key bindings everywhere. Instead of simply 'body'.

That way, any new keybinding added in keymap.cson using the snippet (I assume that's how most people add their first hotkeys) will always override all else by default. As opposed to the current behavior, where new keybindings just added by new users might just be lower priority than something else.

Problems could arise from overriding a native keybinding you might later want. But that's a far easier problem to find/debug/fix than the current one. The default comments on keymap.cson already suggests using the Keybind Resolver to look for conflicts.

@hanslivingstone
Copy link

For anyone else struggling here, I created this package which automatically removes any keybindings (including those from Atom's core) that conflict with what you set in 'keymap.cson': https://atom.io/packages/keymap-control Hope this helps.

@storypixel
Copy link

@hanslivingstone just installed it, so far so good! I was having trouble when atom decided it wanted ctrl-l but i had it for switching to a pane on the right.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests