Suppress backspace behaviour in Chrome?

Hi,

I have what I hope is a quick question. I have a sketch where the user types text onto the screen, and it's written to the screen using a p5 text() call. I have several behaviours tied to keyTyped(), and these work more or less fine, except in Chrome, the BACKSPACE key refuses to not trigger the browser back behaviour, even though I have 'return false;' in my code which is supposed to prevent default browser behaviour (it does prevent other default behaviours in other browsers just fine). Chrome won't even print the keyCode to the console in addition to the annoying "back" behaviour; it just goes back to the previous page. Ideally I'd like my code to work cross-browser, anyone have any ideas? I worry from some googling that this is a common problem with Chrome...

Here's what my code looks like:

function keyTyped() {
    console.log(keyCode);
    if (keyCode == BACKSPACE) {
        currentLine = currentLine.substring(0,currentLine.length-1);
    } else if (keyCode == ENTER) {
        submitAddition();
    } else {
        keyIsTyped(key);
    }
    return false;
}

Answers

  • edited June 2015

    If it's the browser itself taking over some key, I don't think we can do anything about it. :-S
    I've got a "Java-JS" cross-mode sketch which checks for both BACKSPACE & LEFT for deleting 1 character to the left btW. O:-)
    Much probably you're gonna need both keyTyped() & keyPressed() like I did there.
    And before I forget, constant LEFT is LEFT_ARROW in p5.js! :P

    http://studio.ProcessingTogether.com/sp/pad/export/ro.9Zo$UbIWYZEDR/rev.31

  • Yep, unfortunately that code also doesn't "listen" to BACKSPACE properly in Chrome...it triggers a browser back :/...I might have to find a hack-y way around which involves focusing on a DOM input element that's somehow hidden? Or I need to try some of the more pure javascript solutions like this one. It would be easy to tie the delete behaviour to another key, but I'm pretty sure this will result in serious annoyance for users: when you're typing something, you naturally want BACKSPACE to delete to the left - even though I am painfully aware of this little Chrome bug, in testing, I keep pressing BACKSPACE. If it's this annoying for someone who knows about it, I imagine it will be insufferable for users who don't. In googling around it seems I'm not the only one who is annoyed by this 'feature' of Chrome

  • I found a solution that works, but it's pretty ugly...but it works and I need to resolve this and keep going so it's gonna be the final solution.

    Basically, to suppress the backspace behaviour in Chrome, you have to use pure JavaScript or jQuery in the html file (and something to detect browser). I thought pure JS would work inside the p5js sketch, but it won't detect a document.onkeydown(event) function; I'm guessing there's a way around this, but it's probably because there are built in p5 functions that respond to keydown events, and I don't want to mess with those, because they work very well in other browsers and I'm using them elsewhere in my sketch.

    It would still be great if someone a bit better versed in contributing/developing p5.js could add something that allowed backspace use or at least suppression in Chrome more easily. It would be even better if Chrome just killed this feature (or made it opt-in only ) in my opinion. Admittedly tying functions to a backspace press outside an input/text element is perhaps an idiosyncratic thing to want to do, but backspace = navigate back has potentially disastrous consequences for losing data via an inadvertent backspace press when an input field is out of focus.

    Anyway, in the html file set a global boolean, backspace_INCHROME, which will be accessible inside the p5 sketch. I also included bowser.js, which allows really quick, easy browser detection; this way all of this messy stuff I'm doing just won't be triggered for non-Chrome users, since 'return false' after keyTyped() seems sufficient to suppress any built-in BACKSPACE behaviour in other browsers.

    So, the html looks something like this:

           <html>
            <head>
                <script type='text/javascript' >var backspace_INCHROME = false;</script>
                <script language="javascript" type="text/javascript" src="resources/p5.js></script>
                <script language="javascript" src="addons/p5.dom.js"></script>
                <script language="javascript" src="addons/p5.sound.js"></script>
                <script language="javascript" type="text/javascript" src="sketch.js"></script>
                <script language="javascript" type="text/javascript" src="addons/bowser.min.js"></script>
                <script language="javascript" type="text/javascript">
                    document.onkeydown = function (event) {
                        if (bowser.chrome) {
                            var doPrevent = false;
                            var keyCode = event.charCode ? event.charCode : event.keyCode;
    
                        if(keyCode !== 8 ){//if it's not the backspace key, default
                           return;
                        }
    
        var d = event.srcElement || event.target;
                console.log(d.tagName);
                if (d.tagName.toUpperCase() ==="BODY") {
                //!=='INPUT' && (d.type.toUpperCase()!=='TEXT' || d.type.toUpperCase()!=='PASSWORD')) || d.tagName.toUpperCase() !== 'TEXTAREA') {
                  backspace_INCHROME=true;
                  event.stopPropagation();
                  event.preventDefault();
                }
              }
            }
    
          </script>
          <link rel="stylesheet" href="sgstyle.css">
          <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    
          <link rel="stylesheet" href="resources/monokai_sublime.css">
          <script src="resources/highlight.pack.js"></script>
          <script>hljs.initHighlightingOnLoad();</script>
          <!-- this line removes any default padding and style. you might only need one of these values set. -->
          <style> body {padding: 0; margin: 0;} </style>
        </head>
    
        <body>
        </body>
        </html>
    

    What this html code does: if the element focused when backspace is pressed is BODY, it suppresses all behaviour for backspace and sets the global variable backspace_INCHROME to true so p5 can use it. For me, this is fine because the only thing inside BODY is my sketch, but for other pages this could suppress backspace behaviour for text fields etc, inside the BODY. This is probably the first reason this isn't a great solution, but it works in this case and could also for other cases of an entirely p5 webpage. You could also use a p5 instance inside a dom element with a custom id - this would be more of a scalpel approach but right now I'd just like to bludgeon this problem into oblivion.

    In the p5js code, Chrome still suppresses any detection of a BACKSPACE press at all; in other words, this doesn't even register keyDown or keyIsPressed in p5; this is why we need the global backspace_INCHROME variable. When this is set to true from the html, this is read into the draw loop and triggers the backspace behaviour I want, and then resets the variable to false so the behaviour doesn't persist and isn't triggered until the next backspace press.

    function draw() {
        if (bowser.chrome===true) {
            if (backspace_INCHROME===true) {
                //desired backspace behaviour
                currentLine = currentLine.substring(0,currentLine.length-1);
                //reset the boolean
                backspace_INCHROME=false;
            }
        }
    }
    

    I don't love this because generally, throwing events which only occur in certain circumstances (e.g., on a key press) into draw() is not nice; it means this set of if statements is called continuously all the time; this is basically why mouse/key events are built in in the first place, so you can avoid this. But since in Chrome a BACKSPACE keypress doesn't seem to trigger any of the related p5 key events or booleans, I don't see another solution.

    Perhaps in the future something more elegant will present itself, but for now, I'll stick with this quick, ugly, dirty solution so I can move on...

  • What you're trying to do is evil and will be squashed by browser vendors :P

    There are plenty of answers to this question on stack overflow and they all tell the same sorry story: one way or another the browsers block attempts to disable [Back]. Surely the only sane and polite way to do this is with Window.confirm()?

  • OK looking at the original post again it sounds like you're trying to intercept any keyboard presses to generate text, which is why the browser won't play nicely. The answer is to get the user to type text into an element the browser expects them to use BACKSPACE, ergo an input field. If you don't want this cluttering up the screen you can probably use some devious technique to hide it ;)

  • edited June 2015

    I'll eventually have a fully working version of it up and I'll post a link here, but I can't use a text/input field because of the way I need text to move across the screen. It's basically a virtual typewriter, so the paper (and all the text) has to move across the screen (along with the typewriter "carriage") as the string gets longer, and once it hits the edge of the paper, has to shift up as the carriage slides back to the right. This is much, much easier to do with p5 text() than a DOM/input element. In other words, they're not typing text to an input element but into a variable that's called in text(theVariable, theX, theY).

    Every browser is fine with p5 intercepting keypresses (this is what keyTyped( return false;) is for, and there is even a hardcoded keyCode of BACKSPACE in p5 for people who can't be bothered memorising/looking up the digits). It's only in Chrome with the backspace key (and probably some other more obscure keys I haven't tried), that all p5 key events seem to be suppressed; it doesn't register keyPressed as true or trigger keyIsDown().

    It seems a hotly contested issue, but the overall tone seems to be that people hate this, and Chrome is the only hold-out that still insists on it so inflexibly (Safari has removed it, it's easily suppressed in Firefox, which responds to the p5 keyTyped( return false; ) to prevent default browser behaviour). I think it's pretty obvious that while there may be some die-hard "backspace = navigate back" folks, and it's an annoyance when this doesn't work, it's potentially totally catastrophic (e.g., lost posts or forms) when backspace does go back and that's not what you meant to do. Window.confirm() is generally preferred to "suppress" it, but this doesn't let you tie another function to the keypress (and the pop-up is extremely annoying). I don't really want to disable the browser back behaviour entirely; I just want to disconnect it from the backspace key. It would be one thing if BACKSPACE did something you couldn't otherwise do in a browser (alt+left arrow is fine), or disabling it somehow broke the browser, but it doesn't. The backspace=navigate back has far more potential to be catastrophic than backspace=nothing.

  • As I said: I think it should be possible to set the target for input as a 'hidden' form field. What I perhaps didn't say explicitly - but it was implied since the input field is hidden - was that you should of course be able to render the value of the field however you like: e.g. Inside a p5.text(). I'll try and build a proof of concept tomorrow (it's very late here and I should be asleep.)

  • I suspect we're on opposite sides of the Atlantic :). Yes, that is possible, I fiddled with it a little but gave up because I was already down a garden path...the issue I kept running into was that the hidden field easily loses focus.

  • OK - so it turns out my suggestion was a bit old-school. It occurred to me to simply inspect some well known web based 'text editors' to see how they do it and I came across the HTML5 contentEditable attribute.

    This might provide a practical solution: your 'paper' can be a div with the attribute applied and you can manipulate its position as text is added. Assuming it does what you want it may even simplify the task considerably as you won't have to handle a text buffer; but just respond to any keyboard events...

Sign In or Register to comment.