Distinguishing between the hold and release of a modifier key between two keystrokes in Vim

Tag: vim , key-bindings Author: mengmeng151 Date: 2013-04-29

I'd like to make a mapping in Vim so that CtrlTab switches to the previous buffer (:b#), but then if Tab is pressed again without releasing Ctrl, switches to the next buffer (:bn) instead.

This is similar to how the AltTab function in MS Windows works. Is there any way to achieve this effect?
I can't seem to find this question asked anywhere else.

Best Answer

Vim only processes complete key presses; there's only a slight semantic difference in <LeftMouse> vs. <LeftRelease>. You somehow need to process the key chording into different, separate keystrokes (maybe some unused <F13> key?), and can then :map that inside Vim. On Windows, the AutoHotkey tool will let you achieve that.

Alternatively, you could :nmap <C-Tab>, and check whether the previous invocation has happened only recently (using localtime()). That should give you something that works practically as you want.

comments:

I got a fairly elegant solution to this with the AutoHotkey mapping ~Ctrl up::send {F13} and a small vimscript that maps <C-Tab> and <F13>. Thanks for the suggestion!
Yes, that looks good and is what I had in mind. Thanks for posting your full solution; others may be interested in it, too!

Other Answer1

Here is the vimscript I wrote, for anyone interested. I used AutoHotkey to map the release of Ctrl to F13. (See Ingo Karkat's answer)

let g:ctrl_held = 0
let g:prev_buf = 1
function! Ctrltab()
   if g:ctrl_held == 0
      let cmd = ":b".g:prev_buf."\<CR>"
      if g:prev_buf == bufnr('')
         let cmd = ":bn\<CR>"
      endif
      let g:prev_buf = bufnr('') 
      let g:ctrl_held = 1
      return cmd
   else
      return ":bn\<CR>"
   endif
endfunction
nmap <expr> <C-Tab> Ctrltab()
nmap <silent> <F13> :let g:ctrl_held = 0<CR>