I want ctrl-h, ctrl-j, ctrl-k and ctrl-l in insert mode to behave like the arrow keys. I have this (among other things) in my .vimrc:

inoremap <C-j> <Down>   
inoremap <C-k> <Up>
inoremap <C-h> <Left>
inoremap <C-l> <Right>

Now, everything works fine except for ctrl-j. When I press ctrl-j, it will add in a tab right after my cursor position. I thought this might be caused by some of my other setting (like smarttab, shiftwidth, etc.), so I removed every line other than

inoremap <C-j> <Down>

It is still adding the tab. What makes this strange behavior even weirder is that if I open vim with no settings or mappings, and call

:inoremap <C-j> <Down>

it works perfectly fine. But when I call

:source ~/.vimrc

it goes back to adding tabs.

What's causing this? It doesn't make any sense to me that it behaves differently if called from within vim vs sourced from my vimrc. If it makes any difference, I', using gvim on windows 7.


Due to legacy reasons, vim generally treats key events as a terminal emulator would treat them, even in "GUI" versions (e.g. gvim). A terminal emulator would produce e.g. the byte 0x08 for Ctrl-H, which is why the byte is sometimes printed as ^H. The characters @ to _ in the ASCII table (covering the uppercase letters and some symbols) are mapped down to bytes 0x00 to 0x1F when combined with control.

Now, unfortunately some of these low bytes, or control characters, have special meaning: 0x09 turns out to be Tab, 0x0A turns out to be Enter, etc. This has the unfortunate consequence that pressing Enter and pressing Ctrl-J is the same thing in vim—if you change the meaning of one, the meaning of the other changes as well. Even if it would work, I don't think you would want to remap enter in insert mode, so the answer to your question is basically “don't map Ctrl-J in insert-mode”.

Now, in vim it is a bit more complicated than that. When I saw the question I decided to see what gvim in particular does for the different keystrokes... so I pulled up gvim and typed in insert-mode Ctrl-vCtrl-h and so on for the different keys. This gave me ^H^@^K^L. Huh, that's weird, why does Ctrl-j get interpreted as a null byte (^@)?

It turns out (see :h NL-used-for-Nul) that internally vim stores null bytes as line feed characters, and this is what causes the various gotchas with \n and \r in regex patterns. But anyway, not to digress from the topic too much... the main takeaway here I guess is that Ctrl-J is really special in vim, and trying to map it in insert-mode will probably cause more headache than the benefit it provides.

  • I think C-j and RET are different in the underlying terminal already: C-j is carriage return and Return is new line. And vim replaces 0bytes with new line. So c-j is not really special. I could map it in insert and normal mode without problems – johannes_lalala Apr 20 '20 at 11:13
  • Is it safe to map <c-j> to something else in normal/visual mode? – Zaid Gharaybeh May 16 '20 at 4:12

Look at this: https://stackoverflow.com/questions/9092982/mapping-c-j-to-something-in-vim

According to the document of bash-support.vim: The original meaning of Ctrl-j is 'move [n] lines downward' (see |CTRL-j|). If you are accustomed to use the default and don't like these jump targets you can switch them off. Put the following line in the file '.vimrc' : let g:BASH_Ctrl_j = 'off'

You can use that mapping let g:BASH_Ctrl_j = 'off' before your mapping and I guess it should resolve the issue.

  • 1
    Unfortunately, this didn't do anything. I wonder if it's because I'm on windows and not using bash. – James Oct 27 '15 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.