onivim / oni

Oni: Modern Modal Editing - powered by Neovim
https://www.onivim.io
MIT License
11.35k stars 299 forks source link

Is there a way to map Command to Control? #1633

Open trusktr opened 6 years ago

trusktr commented 6 years ago

It'd be great if there was a way to map Command to Control. This would be outside of the Neovim instance, in Electron. Not sure if Electron supports it. Neovim would see it as if we pressed Control, and would not know about this setting.

In iTerm, there's an option to map Command to Control, and Bash will see Control when we're actually pressing Command.

Is this possible?

In macOS, I have Caplock Key mapps to Command, which works great with iTerm (as Control). Would be great to have this in Oni!

bryphe commented 6 years ago

We actually have an API (internal) to support this - we can register KeyResolvers which are a function that take the KeyboardEvent and return a string. They live here today: https://github.com/onivim/oni/blob/115196c8958521abfd1fcf8e885cc28e03560b2b/browser/src/Input/Keyboard/Resolvers.ts#L11

They take KeyboardEvents along with the results of previous resolutions, and output a vim-style string, like <M-v>.

I could see implementing this by adding additional resolvers, along with a config options. For example, we could have a configuration setting input.mapCommandToControl, and a resolver like mapCommandToControl, which would be pass-through if that setting is false, but would otherwise map stuff like <M-v> to <C-v>. We could implement a similar resolver/configuration setting for caps-lock too.

trusktr commented 6 years ago

If I can get Oni ti run manually, I'd like to give this a shot. Let me try to get up an running...

trusktr commented 6 years ago

Alright, got it running (but it's still not ideal). Any pointers on how I might implement this? Where would I start implementing it? In the user config file on activate?

bryphe commented 6 years ago

The user config would be a fine place to try this out, but I could see bringing this in as core functionality too (gated by a config, like tmux).

In theory, something like this should work in config.js:

    oni.input.resolvers.addResolver((evt, key) => {
        console.log(key)
        switch (key) {
            case "j":
                return "k"
            case "k":
                return "j"
            default:
                return key
        }
    })

(Of course, you'd want to have actually logic to map control to meta instead of that simplistic switch case 😄 ). Hope that gives an idea. Otherwise, if you wanted to implement it with our other built-in mappings, you can check out the resolvers we include: https://github.com/onivim/oni/blob/115196c8958521abfd1fcf8e885cc28e03560b2b/browser/src/Input/Keyboard/Resolvers.ts#L11

trusktr commented 6 years ago

About to try when I get home. By the way, I'm interested in command, not meta, swapping it with control. Or, is meta and command the same?

trusktr commented 6 years ago

Are resolvers recursive, or non-recursive? Or both and configurable?

bryphe commented 6 years ago

I don't have an actual Apple keyboard to test, but I believe the command key on Apple maps to meta.

There isn't a concept of recursion with the input resolvers, as they are run prior to any mappings / bindings being involved (which is where recursion would matter). They're really for taking keyboard events and mapping them to the Vim keyboard input string. They are chained and order does matter (addResolver adds to the end of the list and gives priority).

Hope that helps - there's a bit more info here too: https://github.com/onivim/oni/wiki/Input-Management-Architecture#resolution

rgehan commented 6 years ago

I've been looking into this, and it doesn't feel right to have to define bindings manually in the config.js.

I've done it that way:

const CUSTOM_KEYBINDINGS = {
    '<a-bs>': '<c-w>',
    '<m-bs>': '<c-u>',
};

const activate = oni => {
    oni.input.resolvers.addResolver((event, key) => {
        return CUSTOM_KEYBINDINGS[key] || key;
    });
}

IMO, this is useful enough to justify adding a config key and handling this natively (if it isn't already the case). Plus, I don't think it's the user business to create a resolver for such a simple usecase

I can imagine something like that:

// config.js

module.exports = {
    "input.keybindings": {
        "<a-bs>": "<c-w>",
        "<m-bs>": "<c-u>",
    },
};
Deepwalker commented 5 years ago

It is better to have command mapped to <D-, like in vimR.

TalAmuyal commented 5 years ago

I suggest using karabiner elements for Mac.