Search code examples
javascriptinputkeydownsimulate

JavaScript : Simulate Key Events into Textbox/Input


Despite many article on SO on how to simulate key presses (keydown/keypress) in JS, no one solution seems to be working with the browsers I'm using (Firefox ESR 17.0.7, Chrome 28.0.1500.72, IE 10). The solutions I have tested were taken from here, here, and here.

What I'm trying to do is to simulate ANY keystroke in a textarea / input. While I can append / delete characters directly changing "value", I see no option but input simulation for the keys like "Up", "Down", "Home", and some others.

According to the documentation, it should be simple. For example:

var e = document.createEvent("KeyboardEvent");
if (e.initKeyboardEvent) {  // Chrome, IE
    e.initKeyboardEvent("keydown", true, true, document.defaultView, "Enter", 0, "", false, "");
} else { // FF
    e.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, 13, 0);
}
document.getElementById("text").dispatchEvent(e);

indeed fires the "Enter" keydown event, and my handler can catch it. However, it does not affect the textarea in any way - a new line does not appear. Same for other key-codes: characters do not appear, arrows do not change the caret's location, etc.

I have extended the code by Orwellophile and posted it to http://jsfiddle.net/npF3d/4/ , so anyone can play with the code. In my browsers, no button produces any effect on the textarea in any condition.

I would appreciate any help on this issue.


Solution

  • I'm pretty certain that this is a "security" thing, as I've run into the same thing when trying to simulate key presses before.

    Q: How can I type programatically then?
    A: Getting/setting selectionStart, selectionEnd, etc, as well as using these in combination with String methods like slice to insert characters. (See HTMLTextAreaElement reference)

    Q: Why would you still use this kind of event then?
    A: All of the event listeners will work as if it was a real key event.


    Reduced functionality for arrows/home/end can be achieved thusly DEMO

    function homeKey(elm) {
        elm.selectionEnd =
            elm.selectionStart =
                elm.value.lastIndexOf(
                    '\n',
                    elm.selectionEnd - 1
                ) + 1;
    }
    
    function endKey(elm) {
        var pos = elm.selectionEnd,
            i = elm.value.indexOf('\n', pos);
        if (i === -1) i = elm.value.length;
        elm.selectionStart = elm.selectionEnd = i;
    }
    
    function arrowLeft(elm) {
        elm.selectionStart = elm.selectionEnd -= 1;
    }
    
    function arrowRight(elm) {
        elm.selectionStart = elm.selectionEnd += 1;
    }
    
    function arrowDown(elm) {
        var pos = elm.selectionEnd,
            prevLine = elm.value.lastIndexOf('\n', pos),
            nextLine = elm.value.indexOf('\n', pos + 1);
        if (nextLine === -1) return;
        pos = pos - prevLine;
        elm.selectionStart = elm.selectionEnd = nextLine + pos;
    }
    
    function arrowUp(elm) {
        var pos = elm.selectionEnd,
            prevLine = elm.value.lastIndexOf('\n', pos),
            TwoBLine = elm.value.lastIndexOf('\n', prevLine - 1);
        if (prevLine === -1) return;
        pos = pos - prevLine;
        elm.selectionStart = elm.selectionEnd = TwoBLine + pos;
    }
    

    Q: Where does it go wrong?
    A: If lines are long enough to be wrapped, it will treat them as if unwrapped.