Кейлоггер JS неправильно принимает keyup

Я новичок в JS, поэтому я мог сделать какую-то глупую ошибку, но мой кейлоггер, похоже, работает неправильно. Он правильно принимает несколько нажатий клавиш, но когда одно из них отпущено, оно распознает оба нажатия. Любая помощь?

Вот мой код:

var keymap = {};

onkeydown = onkeyup = function(e){
    keymap[e.keyCode] = e.type == 'keydown';

    if(keymap[39] && keymap[32]){ // Right+Space
        jumpRight();

    }

    if(keymap[37] && keymap[32]){ // Left+Space
        jumpLeft();

    }

    if(keymap[32]){ // Space
        jump();

    }

    if(keymap[39]){ // Right
        right();

    }

    if(keymap[37]){ // Left
        left();

    }
}

Я использую Google Chrome, если это поможет.

Спасибо!


person Jacob    schedule 10.10.2017    source источник
comment
Это странный способ сделать это? Вы вообще смотрели на другие решения, прежде чем придумывать собственную странность?   -  person adeneo    schedule 10.10.2017
comment
@adeneo Эта функция кажется мне довольно стандартной, я использовал ее много раз. PS: Не оскорбляйте несколько новичков, которые присоединяются и задают хорошие вопросы.   -  person Feathercrown    schedule 10.10.2017
comment
@Feathercrown - я не оскорбляю, но это странно. Глядя на код, кажется, что правильно было бы просто привязать разные функции к двум событиям, и они используют keyCode непосредственно для сравнения. Я не думаю, что когда-либо видел, чтобы кто-нибудь использовал объект (с числовыми ключами?) для сравнения ключей, даже если вы утверждаете, что использовали его много раз? Я имею в виду, почему бы тебе просто не сделать if (e.which === 39) ... вместо этого.   -  person adeneo    schedule 10.10.2017
comment
@adeneo Хорошо, да, это должен быть массив. Что касается точки массива, то вы можете использовать ключевую информацию вне события нажатия и получить доступ к клавишам, которые удерживаются во время текущего нажатия. НАПРИМЕР. h удерживается, затем игрок нажимает d, теперь вы можете видеть, удерживается ли h этим объектом. Это обычное дело в канвас-играх. Только для однократных ключевых реакций ваш метод достаточен и предпочтителен, поскольку он менее сложен, но не позволяет полностью отслеживать ключи.   -  person Feathercrown    schedule 10.10.2017
comment
@adeneo А что касается использования отдельных операторов if, то это становится слишком длинным. Зачем использовать их, если вы можете обнаружить все ключи одной строкой? По сути, массив используется для хранения, что необходимо для решения этой проблемы (в вопросе) и многих других, таких как отслеживание удерживаемых клавиш, а стратегия не-if короче и захватывает все ключи для размещения в массиве, что обеспечивает легкий доступ по коду клавиши без необходимости добавлять строку для каждой обнаруживаемой клавиши. Использование отдельных переменных с их собственными if для хранения будет работать, но массив, опять же, намного проще в использовании.   -  person Feathercrown    schedule 10.10.2017


Ответы (1)


Я думаю, что он правильно распознает нажатия клавиш, потому что массив обновляется правильно. Проблема в том, что ваши функции (left(), right(), jump() и т. д.) срабатывают только тогда, когда происходит событие нажатия клавиши. Когда вы удерживаете клавишу, иногда она будет продолжать запускать события нажатия клавиши, а иногда нет. Это приводит к тому, что функции не срабатывают, даже если ваша программа знает, что клавиша удерживается нажатой.

Рабочий пример (показывает значения массива все время, а не только при нажатии клавиш; отображаемое значение массива не обязательно означает, что функция срабатывает):

var keymap = {};

onkeydown = onkeyup = function(e){
    keymap[e.keyCode] = e.type == 'keydown';

    if(keymap[39] && keymap[32]){ // Right+Space
        jumpRight();

    }

    if(keymap[37] && keymap[32]){ // Left+Space
        jumpLeft();

    }

    if(keymap[32]){ // Space
        jump();

    }

    if(keymap[39]){ // Right
        right();

    }

    if(keymap[37]){ // Left
        left();

    }
}

document.onkeydown=onkeydown;
document.onkeyup=onkeyup;

function jump(){}
function left(){}
function right(){}
function jumpLeft(){}
function jumpRight(){}

setInterval(function(){console.log(keymap[37]," ",keymap[32]," ",keymap[39]);},5);

Нерабочий пример (как сейчас, показывает значения массива только при нажатии клавиш; показывается значение массива == срабатывает функция):

var keymap = {};

onkeydown = onkeyup = function(e){
    keymap[e.keyCode] = e.type == 'keydown';

    if(keymap[39] && keymap[32]){ // Right+Space
        jumpRight();

    }

    if(keymap[37] && keymap[32]){ // Left+Space
        jumpLeft();

    }

    if(keymap[32]){ // Space
        jump();

    }

    if(keymap[39]){ // Right
        right();

    }

    if(keymap[37]){ // Left
        left();

    }
}

document.onkeydown=onkeydown;
document.onkeyup=onkeyup;

function jump(){console.log("jump");}
function left(){console.log("left");}
function right(){console.log("right");}
function jumpLeft(){console.log("jumpleft");}
function jumpRight(){console.log("jumpright");}

Обратите внимание, что в нерабочем примере ведение журнала происходит только при нажатии клавиши, когда будут вызываться ваши функции. В «рабочем» примере ведение журнала происходит независимо от ключевых событий, но ваши функции все равно не сработают, поскольку они все еще происходят, когда происходят ключевые события. Вот полностью рабочий пример:

var keymap = {};

onkeydown = onkeyup = function(e){
    keymap[e.keyCode] = e.type == 'keydown';
}

document.onkeydown=onkeydown;
document.onkeyup=onkeyup;

function jump(){console.log("jump");}
function left(){console.log("left");}
function right(){console.log("right");}
function jumpLeft(){console.log("jumpleft");}
function jumpRight(){console.log("jumpright");}

function main(){
    if(keymap[39] && keymap[32]){ // Right+Space
        jumpRight();

    }

    if(keymap[37] && keymap[32]){ // Left+Space
        jumpLeft();

    }

    if(keymap[32]){ // Space
        jump();

    }

    if(keymap[39]){ // Right
        right();

    }

    if(keymap[37]){ // Left
        left();

    }
}

setInterval(main,250);

Надеюсь это поможет!

Удачи в изучении JS!

P.S.: Вы пометили left() как "пробел". :П

person Feathercrown    schedule 10.10.2017
comment
@Jacob Вы нажали «Выполнить фрагмент кода», а затем также нажали на появившуюся белую область (страницу)? - person Feathercrown; 10.10.2017
comment
@Jacob Пожалуйста. Еще одно: keymap лучше инициализировать [], чем {}, потому что вы используете цифровые клавиши. - person Feathercrown; 10.10.2017
comment
Ой.. Работает сейчас. Спасибо! - person Jacob; 11.10.2017