How to support keyboard shortcuts?


#1

I have a package. It creates a view and then does

        atom.workspaceView.appendToRight(@myView)
        @myView.focus()

How do I enable keyboard shortcuts in that view? When I hit some keys, they are inserted into the current editor. Do I need special logic in my view?


How to merge 2 packages
Cannot capture core:move-to-top
#2

You could, but no. Make sure you check the examples from the package generator.

You should set keymaps with the css like cson file.


#3

Yes, I created a keymap file, but nothing much is happening. An earlier version had '.atom-svn' instead of '.atom-svn tbody' – neither work. Calling the commands via cmd-shift-P works.


#4

Did you juse cmd+. (keymap resolver) ?


#5

D’oh. Silly me. So now I tried, and the following happened:

  • A jcharacter was inserted into the currently active text editor, at the cursor position.
  • The keybinding resolver mentioned my j binding, but it was greyed out and marked with an X. It said .atom-svn for the selector, and it said svn:next for the command, and it mentioned the right file name.
  • It also mentioned a couple of other greyed out bindings, one of them for Atomatigit and another one for the tree, and then some others.

Additional factoid: The output was the same when the extra svn view wasn’t showing.

I can’t make heads nor tails out of it. It looks to me as if “my” view doesn’t have focus. But I don’t know how to give it focus. I called @focus(), hoping that something meaningful has been inherited from View, but I don’t really have an idea.

I went and peeked in Atomatigit and couldn’t find anything. They didn’t do anything to install the keybindings, and they didn’t do (much) in their focus implementation, either.


#6

So when it’s gray, it’s not hitting your code. You need to make it more specific, try adding extra classes to the dom and then mirror that in your map like .class1.class2.class3

so, <div class=“class1 class2 class3”

See if you win in specificity.


#7

Well, some things to know about how the Keybinding Resolver works:

  1. It selects the right keybinding based on specificity (see the Specificity and Cascade Order section) as well as which view has focus
  2. The one keybinding that is a different color than the others is the one that “won”

#8

I think it’s not a specificity problem. I’ve now done two things. First, my original keybindings were j and k, and I didn’t get any “selected” entry in the list of keyboard shortcuts. So now I’ve mapped ctrl-n and ctrp-p, and this allows me to see a little more:

From my layman’s perspective, it looks as if body .workspace .atom-svn should be a (much) more specific selector than the body selector that won.

I think my next step is to create a little dummy package that does nothing but to showcase the issue. If the dummy package doesn’t have an issue, I can compare to see what’s going wrong with atom-svn. If the dummy package also has the same issue, then we can all look at just a few lines of code to see the issue, and I hope it’s easier to make suggestions about a few lines of code.


#9

Okay. I have now created a package that demonstrates the problem. I have made minimal changes to the standard package created when using the package generator.

The github repo explains how to test it out.

If you don’t want to read the whole thing, here is a description of my changes. I changed keymaps/focus.cson to add the following lines:

'.focus':
  'ctrl-b': 'focus:beep'

I made a few changes to lib/focus-view.coffee. I changed the content as follows:

  @content: ->
    @div class: 'focus', =>
      @div "The Focus package is Alive! It's ALIVE!"
      @div outlet: 'focusBeep'

I added the “beep” command in the initialize method:

  initialize: (serializeState) ->
    atom.workspaceView.command "focus:toggle", => @toggle()
    atom.workspaceView.command 'focus:beep', => @beep()

I changed the method toggle to use appendToRight instead of append, and to call focus explicitly:

  toggle: ->
    console.log "FocusView was toggled!"
    if @hasParent()
      @detach()
    else
      atom.workspaceView.appendToRight(this)
      @focus()

I added the new method beep:

  beep: ->
      @focusBeep.append('<p>Beep!</p>')

The only other file I changed was the README – I’ll skip that one.

Help?


#10

It’s really weird; I’ve now added an “option” (you have to edit the code) to show the output of svn status either in a side bar, like Atomatigit does it, or in its own tab (like editors).

If I make it create a new tab, then the new tab supports almost no keybindings, not even the standard bindings cmd-shift-[ and cmd-shift-] (and ctrl-tab) to switch between tabs work. (I can use cmd-shift-] to switch to the tab, but once I’m on the tag that shows “svn status”, I can’t switch away from it using cmd-shift-].) The only keybinding (that I found) that works is cmd-w. Go figure.

Here is the output of the keybinding resolver on ctrl-n. I can’t interpret it. There must be something fundamental I’m missing.


#11

It appears like what you’re missing is the concept of a “selection”. For example, you mention the automatigit package. If you look at its keymap:

'.platform-darwin .atomatigit':
  'cmd-alt-g': 'atomatigit:close'

'.platform-win32 .atomatigit, .platform-linux .atomatigit':
  'ctrl-alt-g': 'atomatigit:close'

'.atomatigit .file-list-view, .atomatigit .branch-list-view, .atomatigit .commit-list-view':
  'down': 'atomatigit:next'
  'j': 'atomatigit:next'

The only thing that is mapped to the outermost class of the view is “close”, which, it appears, is the only thing you can get to work at that level. But things like down arrow or j are mapped to classes for views which support the concept of a “selected item” … over and above “focus”, which is what you seem to have been relying on so far.

Maybe that has something to do with it?


#12

I’ve got two packages, one is the focus test, and it’s got a command “beep” that doesn’t rely on any selection. Calling it by cmd-shift-P works, calling it by ctrl-b does not work.

The other package is atom-svn, it’s got the concept of a selection (one of the table rows is highlighted because it has the CSS class “selected”), and there are commands svn:previous and svn:next that modify the selection. Calling both commands by cmd-shift-P works, calling them by any keybinding does not work.

The focus test package only has one mode, the Atomatigit like mode where its view is shown on the right. When I hit the keybinding in that case, it is executed in the editor that currently has focus.

The atom-svn package has two modes, the Atomatigit like mode and a mode where its view is shown as a separate tab. When I hit the keybindings in the Atomatigit like mode, it’s like the focus test package – the keybindings get executed in the currently focused editor. When I hit the keybindings in the “show separate tab” mode, they get swallowed silently.

I also have a third package, atom-man, where keybindings work. But it has a totally different machinery: it registers itself as an opener for certain URIs.

I’m really really confused.


#13

FWIW, I’ve now added the feature to atom-svn that you can click on a file to select it. That works fine. But the keybindings still don’t work. (Calling the commands with cmd-shift-P still works fine.)


#14

This is now solved; it was a focus issue after all, and not a specificity issue.

Though some HTML elements accept focus by default (and you can tab through them), most HTML elements do not. If you would like such an element to receive focus, you have to add a value for the tabindex attribute.

So what I did was this:

  • Augment the root element of my view by adding tabindex: -1:

      @div class: 'atom-svn', tabindex: -1, =>
    
  • Make sure the keys are defined with that element as the selector:

      '.atom-svn':
              'ctrl-n': 'svn:next'
    

This way, the problem is solved.

I had compared my view with the Atomatigit view and I had seen this difference, but didn’t think it was important. Boy, was I wrong.

I figured this out when I was using Redmine at work: when you visit a project in Redmine, you get a tab bar, and when you select a tab (I selected the “Issues” tab), you see a little dotted border around the tab. The same dotted border that’s used to indicate focus. So I thought, wow, they somehow were able to provide focus to the div and not to the link inside it. So then I Googled for how to allow keyboard focus for HTML elements in HTML apps, and that found the solution.

Here is a Stackoverflow answer:


#15

I guess you guys are veteran HTML/JS hackers, but I’m just getting into this, so it wasn’t obvious at all.


#16

Heh, another trick, that may or may not help in the future for this kind of thing (events) is:
After opening up inspect / console, going to sources -> Event Listener Breakpoints (on right hand side) -> Keyboard …also XHR is SUPER useful also.


#17

I :heart: you. Thanks so much for this detailed writeup.