0

I'm trying to implement Vim-like hotkeys for my project; first and foremost, I've decided to realise j and k bindings, so I've wrote this KeyboardEvent handler:

window.onkeydown = function( event ) {
    if (event.code === 'KeyJ')
        window.scrollBy({ top: 128, behavior: 'smooth' });

    else if (event.code === 'KeyK')
        window.scrollBy({ top: -128, behavior: 'smooth' });
};

Seems legit, right? Actually — no: when I holding j or k the scrolling process becomes disjointed and teared (also it's seems like the scroll speed is cutted in a half, like if 64 would be added to scrollTop instead of 128).

Can I somehow directly map k to and j to using plain JavaScript?


I've tried this solution:

const ArrowUp = new KeyboardEvent( 'keydown', { code: 'ArrowUp' } );
const ArrowDown = new KeyboardEvent( 'keydown', { code: 'ArrowDown' } );

window.onkeydown = function( event ) {
    if (event.code === 'KeyJ')
        window.dispatchEvent( ArrowDown );

    else if (event.code === 'KeyK')
        window.dispatchEvent( ArrowUp );
};

But it doesn't work at all, I do not even get any errors .

  • Why no one answers? Is question unclear? If so, tell me, please. I do not believe I'm the only one faced the problem I've described. – Monsieur Pierre Doune Dec 02 '19 at 20:27
  • You should look at this: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events. The reason your last code is not working is because nothing is listening to those events. And the reason your first code is glitchy is probably because you're trying to start a smooth transition on every update while a key is down. – Glenn van Acker Dec 03 '19 at 08:29
  • @GlennvanAcker even without smooth-scrolling everything is glitchy as hell, unlike default arrow-scrolling, whether smooth-scrolling enabled or not. – Monsieur Pierre Doune Dec 03 '19 at 08:36

1 Answers1

1

I have two solutions. This first solution is a bit... let's just say it's not great. You can force it to only listen to the events every so often to prevent the glitchy-ness.

var lastScrollTime = Date.now();
window.onkeydown = function( event ) {
    var d = Date.now();
    if(d - lastScrollTime < 64){
        return;
    }
    lastScrollTime = d;
    if (event.code === 'KeyJ')
        window.scrollBy({ top: 128, behavior: 'smooth' });

    else if (event.code === 'KeyK')
        window.scrollBy({ top: -128, behavior: 'smooth' });
};

My second solution is a bit better by still by no means great. You could implement your own smooth scrolling system.

var scrollTo = 0;
function lerpTo(){
    var newPt = lerp(scrollTo, window.scrollY, 1.1);
    console.log(newPt);
    window.scrollBy(0, window.scrollY - newPt);
}
function lerp(v0, v1, t) {
    return v0*(1-t)+v1*t
}
setInterval(lerpTo, 20);

Then with that, all you have to do is change 'scrollTo' whenever you press j or k. Now that code used a lerp function. If you wanted more consistent motion you could change it out for a fixed amount. The big downside to that one is you can no longer scroll normally. To re-add normal scrolling you would have to listen to that event and set scroll to again, however I think that is a bad solution. Alternatively, to add normal scrolling again you could disable the lerp code whenever you scroll manually, then re-enable it whenever someone presses j or k.

Strike Eagle
  • 852
  • 5
  • 19