Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flexible keymap (hotkeys / shortcut) #872

Closed
iamstarkov opened this issue Oct 13, 2016 · 18 comments
Closed

Flexible keymap (hotkeys / shortcut) #872

iamstarkov opened this issue Oct 13, 2016 · 18 comments
Labels
💬 Feedback Wanted Issue or PR needs input from the community! Lend your thoughts ✨ ❣️ Priority: High Issue is of High priority 👩‍🔬 Status: In Progress Issue or PR is currently active and work is in progress 🎨 Type: Enhancement Issue or PR is an enhancement request/proposal for Hyper

Comments

@iamstarkov
Copy link
Contributor

the important key to achieve it in flexible and reliable way is to have two things:

  • list of possible events to rpc.emit 1
  • one place to bind keys to those events

1 Note: rpc bus should be the only way to broadcast key events).

Initial array of events can be collected from lib/index.js#L38-L129: like split request vertical or split request horizontal, etc.

Then in config we can do smth like this:

keymap: {
 "CmdOrCtrl+Alt+Left": "prev pane req",
}

where keys are electron accelerators and values are those events for rpc to emit/receive.

After that, we need to modify attachKeyListeners() lib/containers/hyper.js#L38-L76 to not bind hardcoded keys, but instead to pick up keys and events from keymap:

// mousetrapify needs to be more advanced, for sure, but this is enough for now
const mousetrapify = key => key.replace('CmdOrCtrl', 'mod').toLowerCase();
Object.keys(this.config.keymap).map(item => {
  const accelerator = item;
  const event = this.config.keys[key];
  keys.bind(
    mousetrapify(accelerator),
    () => {
      if (focusedWindow) {
          focusedWindow.rpc.emit(event);
      }
    }
 );
})

Also, Hyper needs to verify that this.config is merged object similar toObject.assign({}, defaultConfig, ...[pluginsAndThemesConfigs], userConfig)

Thats it.


One interesting benefit of proposed approach is that you can update menu accelerators very easy and smooth. just needs to write a function which will lookup desired accelerator by key event relevant to that menu item. 2, 3

const findAccelerator = event => Object.keys(this.config)
  .map(key => { key, value: this.config[key] })
  .find({ value } => value === event)
  .key

Result

what do you think?

@iamstarkov
Copy link
Contributor Author

i want to discuss this approach before i will start implementation, so any feedback is welcomed: ideas, questions, concerns, problems, etc

@iamstarkov
Copy link
Contributor Author

@leo @codetheory @ekmartin @rauchg what do you think?

@matheuss matheuss added 🎨 Type: Enhancement Issue or PR is an enhancement request/proposal for Hyper 💬 Feedback Wanted Issue or PR needs input from the community! Lend your thoughts ✨ labels Oct 13, 2016
@timothyis timothyis changed the title feature proposal: flexible keymap (hotkeys / shortcut) Flexible keymap (hotkeys / shortcut) Oct 13, 2016
@ekmartin
Copy link
Contributor

I'm not sure if it's a good idea to bind keybindings to rpc directly. Far from all combinations have an rpc event connected to them at the moment, so not sure if that's a good direction to go.

Why not have a separate keymap file that maps a string key to a combination? I.e. 'split-vertical': 'Cmd+D'. That way the keymap config could be used both in the menu decorator and in the hyper container.
We could then expose the keymap to plugins in the same way we do with a regular config.

Example would be: keys.bind(keyMap['move-right'], moveRight).

@iamstarkov
Copy link
Contributor Author

iamstarkov commented Oct 13, 2016

I'm not sure if it's a good idea to bind keybindings to rpc directly.

maybe its not a good idea, but rpc as a central piece of code for key bindings — is the best point i could think of. To be honest, in the end it can be not a rpc, but any central broadcast communication api. It just happens, that rpc is what we have now.


Far from all combinations have an rpc event connected to them at the moment, so not sure if that's a good direction to go.

We can add them later, once proposed changes will be in place, it should be easy.


Why not have a separate keymap file that maps a string key to a combination?

main reason against two files over one, is simplicity: harder to show/sync your settings with two configuration files You may think that configuration file with a whole keymap will be too hard to read, though to cure this problem we need to think careful about sane default keymap.


I.e. 'split-vertical': 'Cmd+D'. That way the keymap config could be used both in the menu decorator and in the hyper container.

Exactly! I'm all for that as i mentioned in proposal.

Need to note, that keybinding: rpcEvent have to be reversed, because relation is not one keybinding to multiply rpcEvents, but quite opposite — one rpcEvent to many keybindings. And hey, its how its done in Atom, which i cant blame for blame for bad keymap decisions.


We could then expose the keymap to plugins in the same way we do with a regular config.

Yep!


Example would be: keys.bind(keyMap['move-right'], moveRight).

Kinda, as far as pairs are revered you have to do smth like this:

Object.keys(this.config.keymap).map(accelerator => {
  const event = this.config.keys[key];
  keys.bind(
    mousetrapify(accelerator),
    () => { rpc.emit(event); } // kinda
 );
})

@iamstarkov
Copy link
Contributor Author

tldr:

  • one file is simpler than two
  • for this feature to work we need broadcast mechanism, lets start with rpc for now
  • pair should be keybinding: event

@jwhitley
Copy link

I'll argue for an approach to keybindings that guarantees sensible rebinding and/or unbinding. A concrete example:

When using iTerm2, I rebind the ⌘1 through ⌘9 keys globally (across all profiles). Instead of their normal function of switching the first nine iTerm2 tabs, they instead are bound to emit <prefix>-<num> which switches between tmux windows. I.e. I use tmux so heavily that I prefer the normal Command bindings to treat tmux windows like tabs.

Another frustration of some keybinding systems (vim, I'm lookin' at you) is that not all bindings are first-class and/or introspectable. I.e. there's no command or API that can ask such questions as:

  1. What are all the currently active keybindings?
  2. What key(s) are bound to operation <foo>?
  3. What operation(s) are bound to key-sequence <bar>?
  4. (Bonus points) Where did a given binding come from? (e.g. user config, plugin baz, etc.)

These operations aid both config debugging and discoverability.

@iamstarkov
Copy link
Contributor Author

@jwhitley After and if proposed change will land in master. All keybindings will be declared in one keymap object, and it will be possible to redefine them in your config.keymap

@iamstarkov
Copy link
Contributor Author

bad news everyone, Hyper has two rpc, one for Electron and one for Renderer processes, and you cant share them. problem here is that key bindings in ./lib/containers/hyper.js can be used to emit event only to to Renderer's rpc, while actual rpc responsible for hotkeys is Electron's one

@iamstarkov
Copy link
Contributor Author

iamstarkov commented Oct 20, 2016

on the other note, there is another way

iamstarkov added a commit to iamstarkov/hyper that referenced this issue Oct 23, 2016
iamstarkov added a commit to iamstarkov/hyper that referenced this issue Oct 23, 2016
@iamstarkov
Copy link
Contributor Author

This PR #925 is another approach, i was talking about

@iamstarkov
Copy link
Contributor Author

iamstarkov commented Feb 9, 2017

@rauchg can i ask you to move labels from #925 PR into this original issue? Priority: High, Status: Community feedback wanted, Status: In Progress. And pls share your thoughts about last one

@ppot
Copy link
Contributor

ppot commented Feb 10, 2017

@iamstarkov I switched the label

@ppot ppot added ❣️ Priority: High Issue is of High priority 👩‍🔬 Status: In Progress Issue or PR is currently active and work is in progress labels Feb 10, 2017
@ppot
Copy link
Contributor

ppot commented Feb 10, 2017

Plz add request inside issue: ppot#11

@andrroy
Copy link

andrroy commented Apr 5, 2017

Referring to the label "In progress", is this issue actively being worked on? All i could find was @iamstarkov closed PR.

@iamstarkov
Copy link
Contributor Author

@andrroy look at ppot#11

@iamstarkov
Copy link
Contributor Author

and yes it is in progress

@iamstarkov
Copy link
Contributor Author

here #1509

This was referenced Apr 30, 2017
@ppot
Copy link
Contributor

ppot commented Aug 15, 2017

close in #1876

@ppot ppot closed this as completed Aug 15, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💬 Feedback Wanted Issue or PR needs input from the community! Lend your thoughts ✨ ❣️ Priority: High Issue is of High priority 👩‍🔬 Status: In Progress Issue or PR is currently active and work is in progress 🎨 Type: Enhancement Issue or PR is an enhancement request/proposal for Hyper
Projects
None yet
Development

No branches or pull requests

6 participants