Keydown обрабатывает предыдущий символ вместо текущего

Я пытаюсь создать окно эмуляции MS-Dos с помощью jquery и ajax. Он работает хорошо, но когда я набираю слово или нажимаю клавишу ввода, сценарий отображается на один символ слишком поздно (при первом нажатии символ не отображается, затем для каждого следующего нажатия клавиши он показывает предыдущий символ, введенный пользователем, вместо текущего). ).

Вот упрощенная версия моего скрипта:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="css/terminal.css">
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function() 
            {       
                //set cursor position
                $('#cursor').css('left','0px');

                //focus on textfield
                $('#field').focus();

                //On key down...
                $('#field').keydown(function(event) 
                {
                    request=$(this).val();
                    count=$(this).val().length;

                    //Display chars as they come
                    $("#instruct").html(request);

                    // If "enter" is pressed
                    if (event.which == 13) 
                    {
                        event.preventDefault();

                        //clean user entry
                        request=request.replace(/\n/g, "");

                        // Process user entry
                        $.ajax({
                              type: "POST",
                              url: "scripts/ajax/terminal.php",
                              data: {command:request},
                              success: function(response) 
                              {
                                // if user typed something before pressing "enter"
                                if(response !='')
                                {
                                    // update list by logging the previous entry, showing system response and clearing the textarea
                                    $('#log').append("<li class='user'>--- &gt;<span>"+request+"</span></li>");
                                    $('#log').append("<li class='sys' >SYS &gt;<span>"+response+"</span></li>");
                                    $('#field').val('');
                                }
                              }
                        }); 
                    }
                });             
            });
        </script>   
    </head>

    <body>
        <ul id="log">
            <li class='sys'>Sys &gt;<span>Identification required</span></li>
        </ul>

        <ul id="realtime">
            <li id="live-space">
                <span class="user-line">--- &gt;</span>
                <textarea type="text" id="field"></textarea>
                <div>
                    <span id="instruct"></span><div id="cursor">_</div>
                </div>
            </li>
        </ul>
    </body>
</html>

Я уверен, что "keyDown" запускается, когда это необходимо, потому что, когда я меняю это

$("#instruct").html(request);

в это

$("#instruct").html(request+'x');

... «x» появится сразу после первого нажатия клавиши, в то время как содержимое «запроса» будет отложено до следующего нажатия клавиши (например, если я наберу «a», я увижу только «x» и когда я наберу "б" сразу после, я вижу "топор" и т.д...).

Таким образом, речь идет не о нажатии клавиши, а о выборе правильного символа в нужное время.

Что я делаю неправильно?

Спасибо.


person Baylock    schedule 25.12.2012    source источник
comment
Я пробовал keydown, keypress и keyup. Каждый по отдельности (у них одна и та же проблема) или любая их комбинация вместе. Если я использую три из них для запуска одной и той же функции, у меня есть что-то, что выглядит почти правильно. Но некоторые другие навороты (например, перемещение курсора) сходят с ума (курсор будет перемещаться 3 раза вместо одного каждый раз, когда я нажимаю клавиша со стрелкой и т. д.). Дело в том, что он должен работать только с keyDown, верно?   -  person Baylock    schedule 25.12.2012
comment
@Baylock: Не должно, и я описываю, почему в своем ответе: вы слишком рано.   -  person Amadan    schedule 25.12.2012
comment
магия ключевого события   -  person mayankcpdixit    schedule 08.09.2015


Ответы (2)


Рабочая демонстрация

Значение поля не обновляется до того, как вы его поймаете, просто добавьте символ нажатой клавиши, но String.fromCharCode(event.which) возвращает символ в верхнем регистре, если вы используете keydown, поэтому используйте keypress

$('#field').on('keypress',function(event){
    request=$(this).val() + String.fromCharCode(event.which);
    ...

или вы могли бы использовать

$('#field').on('keyup',function(event){
    request=$(this).val(); // value is ready by now
    ...

но обратная связь появляется медленнее, потому что вы ждете отпускания клавиши

person Popnoodles    schedule 25.12.2012
comment
Это почти нормально, спасибо! Одна последняя проблема: текущий символ в верхнем регистре. Когда я набираю новый символ, предыдущий становится строчным (а новый — прописным и т. д.) - person Baylock; 25.12.2012
comment
Почти идеально с нажатием клавиш (нажатие клавиш недостаточно отзывчиво для набора текста в реальном времени). Больше нет проблем с верхним регистром, и символы ведут себя так, как я ожидаю, НО мне все еще нужно дважды нажать Enter, чтобы увидеть ответ системы. Я полагаю, что fromcharcode не учитывает разрыв строки, не так ли? - person Baylock; 25.12.2012
comment
Я не понимаю, почему вам нужно дважды нажать Enter - person Popnoodles; 25.12.2012
comment
Я возвращаюсь к этому снова, так как нажатие клавиши недостаточно хорошо ... Мне нужно использовать стрелки клавиатуры (вместе с сдвигом и т. д.), а нажатие клавиши имеет дело только с печатными символами. Итак, я вернулся к квадрату два, а именно: как использовать нажатие клавиши вместо нажатия клавиши без проблем с прописными буквами? PS: я попробовал обработчик события change(), но ничего не могу добиться. Мой скрипт просто зависает, когда я это делаю. PPS: я немного читал о keydown(), и кажется, что он не чувствителен к регистру, только в верхнем регистре, поэтому я считаю, что нахожусь в рассоле. Как люди обычно делают, чтобы писать в реальном времени с помощью javascript? - person Baylock; 25.12.2012
comment
Используйте event.charCode вместо event.which - person Andre Figueiredo; 01.04.2014
comment
плюс, я не понимаю, почему $(this).val() лучше, чем vanilla JS this.value в этом случае... - person Andre Figueiredo; 01.04.2014
comment
$(this).val() лучше, чем vanilla JS this.value в этом случае только потому, что человек делает jQuery. - person Popnoodles; 02.04.2014

Это о времени. На момент события keydown элемент управления еще не получил символ - по сути, он даже не уверен, получит ли он его (поскольку вы можете заблокировать keydown или keypress, а он добавляется только после него). Поэтому, когда вы читаете содержимое своего элемента управления, вы делаете это слишком рано — это все равно, что пытаться съесть гамбургер, когда вы решили пойти в Макдональдс, а не после того, как вы пошли и заплатили за него.

Вы можете прочитать больше о событиях клавиатуры здесь, и немного подробнее в здесь.

Решение: keydown предназначен не для этого. Попробуйте и посмотрите, подходит ли вам событие change лучше. РЕДАКТИРОВАТЬ: я имел в виду, поймать персонажей, когда они приходят с событием change. Поймайте клавишу Enter с помощью keydown, как вы это делали.

person Amadan    schedule 25.12.2012
comment
Спасибо за ваш вклад. Это то, что я имел в виду, но что было бы решением, чтобы заставить это работать? ТИВМ - person Baylock; 25.12.2012
comment
Кажется, я написал объяснение проблемы. Если я отказался от небольшой версии сценария, то это потому, что я не был уверен, что это теоретическая проблема. Это могло быть отсутствие логики в моих инструкциях по javascript. - person Baylock; 25.12.2012
comment
Ааааа я не умею читать. Извините, должно быть, было позже, чем я думал. Извинения. - person Amadan; 25.12.2012