chjj / blessed

A high-level terminal interface library for node.js.
Other
11.27k stars 533 forks source link

duplication of input #109

Open kicumkicum opened 9 years ago

kicumkicum commented 9 years ago
  1. focus to textarea
  2. enter charectes abc
  3. focus to List
  4. hide List and focus to another List
  5. focus to textarea
  6. enter charectes abc, but result aabbcc

I see this behavior in my app vknplayer, after update blessed from 0.0.47 to 0.0.48 What could be the reason?

chjj commented 9 years ago

@kicumkicum, are you using the latest blessed? There was a race condition with binding key listeners on textareas a little while ago, but it was fixed.

KalenAnson commented 9 years ago

I'm also seeing this kind of behavior with Blessed 0.1.7.

If I have two textbox elements, boxOne and boxTwo and define an on('click'... event that does nothing, i.e.:

boxTwo.on('click', function(data) {
  // Nothing
});

If boxOne was focused for input and I now click onto boxTwo, boxTwo does not receive focus and any further typing in boxOne will be duplicated.

Additional calls to a focus() method on another element can cause this input to be quadruplicated.

Not quite sure whats going on here but I will be happy to provide more info.

kicumkicum commented 9 years ago

I use blessed 0.1.81 I have two blessed.list and one blessed.textarea I loging remove listener in readInput and add listener in nextTick. task keys:

kkirby commented 8 years ago

Any update on this?

m4rky77 commented 8 years ago

I revert this commit https://github.com/chjj/blessed/commit/b42308c7cc3e544821254a0095082d22b60f5af9 and work for my, but i don't know what i'm doing.

bradparks commented 7 years ago

I'm still getting this issue, and I think it happened because I have multiple controls listening for the escape key on input, and then refocusing a textbox on this happening. When I removed this callback, it stopped happening.

program.key('escape', function() {
  text.focus();
});

blessed 0.1.81

acunniffe commented 5 years ago

In case anyone else has this issue I created a workaround that does not require a fork. You can use this function to add a working inputFocus and inputBlur to a textbox instance. This will cleanup the listeners on blur that cause the duplication.

export function AddBlurToTextBox(textBox, handlers) {
    textBox.inputFocus = () => {
        textBox.inputBlur()
        textBox.addHandlers()
        textBox.focus()
    }

    textBox.addHandlers = () => handlers()

    textBox.inputBlur = () => {
        textBox.removeListener('keypress', textBox.__listener);
        delete textBox.__listener;

        textBox.removeListener('blur', textBox.__done);
        delete textBox.__done;
        textBox.screen.focusPop(textBox)
    }
}

Usage: Note you must add all your handlers to the callback so they can be reattached on focus

AddBlurToTextBox(input, () => {
        input.on('keypress', (ch, key) => {
                 //do something
    })
})

Clearly not ideal -- but I don't want to own this code by forking it

rajasegar commented 4 years ago

For me , removing the explicit focus handler for the textbox and setting the option inputOnFocus: true solves this issue.

Trackhe commented 4 years ago

I have the same Problem. but i use it only for an intro and i destroy after that the screen. after that i use inquirer for questions and dubble input. @acunniffe i dont now but i cant get working your fix for me.

module.exports = ({screen, box, image, bigtext}, callback) => {
    const sc = screen({
        smartCSR: true
    });

    const bx = box({
        parent: sc,
        height: "100%",
        width: "100%",
        optimierung: "cpu",
    });

    sc.append(bx);

    let i = 100;

    let img = image({
        parent: bx,
        top: 0,
        left: i + "%",
        width: "34%",
        height: "100%-14",
        type: "ansi",
        ascii: "density",
        file: __dirname + "/../../img/Mond.png",
    });

    bigtext({
        parent: bx,
        content: "MoonShop",
        top: "100%-14",
        style: {
            fg: "white",
        },
        left:"center",
        align:"center",
        valign:"middle",
    });

    function AddBlurToTextBox(sc, handlers) {
        sc.inputFocus = () => {
            sc.inputBlur();
            sc.addHandlers();
            sc.focus();
        };

        sc.addHandlers = () => handlers();

        sc.inputBlur = () => {
            sc.removeListener("keypress", sc.__listener);
            delete sc.__listener;

            sc.removeListener("blur", sc.__done);
            delete sc.__done;
            sc.screen.focusPop(sc);
        }
    }

    AddBlurToTextBox(sc, () => {

    });

    function intro(){
        if(i > 33){
            i--;
            img.left = i + "%";
            sc.render();
            setTimeout(intro,50);
        } else {
            setTimeout(() => {
                sc.destroy();
                console.clear();
                callback();
            }, 4000);
        }
    }
    intro();
};
jayk commented 11 months ago

For Whatever it's worth, I spent quite a while battling this problem and finally came up with a working solution based on @acunniffe's code. My slightly modified version is below.

function AddBlurToTextBox(textBox, handlers) {
        textBox.inputFocus = () => {
                textBox.inputBlur()
                textBox.addHandlers()
                textBox.focus()
        }

        textBox.addHandlers = () => handlers()

        textBox.inputBlur = () => {
                setImmediate(() => {
                    textBox.removeListener('keypress', textBox.__listener);
                    delete textBox.__listener;

                    textBox.removeListener('blur', textBox.__done);
                    delete textBox.__done;
                });
        }
}

In my code, I just call the inputBlur() in my submit handler. - when the input is focused again it behaves normally.

The issue seems to be that TextArea is adding it's listeners in a nextTick() (which is really setImmediate()) - which means just removing them doesn't work because they don't exist yet. Putting the removal in a setImmediate makes the removal happen after they are actually added. No more key duplication. :)