¿Cómo detectar si la tecla presionada producirá un carácter dentro de un cuadro de texto <input>?

Resuelto Šime Vidas asked hace 14 años • 16 respuestas

Tengo un cuadro de texto normal:

<input type="text"> 

Utilizo jQuery para manejar eventos relacionados con claves:

$("input:text").keydown(function() {
    // keydown code
}).keypress(function() {
    // keypress code
}).keyup(function() {
    // keyup code
});

El usuario se centra en un cuadro de texto y pulsa varias teclas de su teclado (las habituales: letras, números, SHIFT, RETROCESO, ESPACIO, ...). Necesito detectar cuando el usuario presiona una tecla que aumentará la longitud del valor del cuadro de texto. Por ejemplo, la tecla "A" lo aumentará, la tecla "SHIFT" no.

Recuerdo haber visto una conferencia de PPK donde mencionó la diferencia entre esos dos. Tiene algo que ver con el evento (pulsación de tecla versus pulsación de tecla) y posiblemente con las propiedades del evento: clave, carácter, código de clave.

¡Actualizar!

Necesito conocer esta información dentro de los controladores de pulsación de tecla o pulsación de tecla. No puedo esperar a que se produzca el evento de keyup.

Por qué necesito esto:

Tengo un cuadro de texto cuyo tamaño cambia dinámicamente según la entrada del usuario. Puedes echar un vistazo a esta demostración: http://vidasp.net/tinydemos/variable-size-text-box.html

En la demostración, tengo un controlador de pulsación y activación de teclas. El controlador de teclas ajusta el tamaño del cuadro de texto según el valor de entrada. Sin embargo, el controlador de pulsación de tecla establece el tamaño en 1 carácter más grande que el valor de entrada. La razón por la que hago esto es que si no lo hiciera, el carácter se desbordaría fuera del cuadro de texto y solo cuando el usuario soltara la tecla, el cuadro de texto se expandiría. Esto parece raro. Es por eso que tengo que anticipar el nuevo carácter: amplié el cuadro de texto en cada pulsación de tecla, ergo, antes de que el carácter aparezca en el cuadro de texto. Como puede ver en la demostración, este método se ve genial.

Sin embargo, el problema son las teclas RETROCESO y FLECHA: también expandirán el cuadro de texto al presionar la tecla, y solo al presionar la tecla se corregirá el tamaño del cuadro de texto.

Una solución alternativa:

Una solución alternativa sería detectar las teclas RETROCESO, MAYÚS y FLECHA manualmente y actuar en base a eso:

// keydown handler
function(e) {
    var len = $(this).val().length;
    if (e.keyCode === 37 || e.keyCode === 39 ||
        e.keyCode === 16) { // ARROW LEFT or ARROW RIGHT or SHIFT key
        return;
    } else if (e.keyCode === 8) { // BACKSPACE key
        $(this).attr("size", len <= 1 ? 1 : len - 1);
    } else {
        $(this).attr("size", len === 0 ? 1 : len + 1);
    }
}

Esto funciona (y se ve muy bien) para RETROCESO, MAYÚS, FLECHA IZQUIERDA y FLECHA DERECHA. Sin embargo, me gustaría tener una solución más sólida.

Šime Vidas avatar Nov 15 '10 04:11 Šime Vidas
Aceptado

Creo que esto funcionará, o si no, está muy cerca y solo necesitará pequeños ajustes. Lo que debe recordar es que no puede decir nada de manera confiable sobre ningún carácter que pueda escribirse en un evento keydowno keyup: todo debe hacerse en un keypresscontrolador. El recurso definitivo para eventos clave es http://unixpapa.com/js/key.html

También debes considerar las pastas, que este código no manejará. Necesitará tener pasteun controlador de eventos independiente (aunque este evento no es compatible con Firefox < 3.0, Opera y navegadores WebKit muy antiguos). Necesitará un temporizador en su controlador de pegado, ya que en JavaScript es imposible acceder al contenido que está a punto de pegarse.

function isCharacterKeyPress(evt) {
    if (typeof evt.which == "undefined") {
        // This is IE, which only fires keypress events for printable keys
        return true;
    } else if (typeof evt.which == "number" && evt.which > 0) {
        // In other browsers except old versions of WebKit, evt.which is
        // only greater than zero if the keypress is a printable key.
        // We need to filter out backspace and ctrl/alt/meta key combinations
        return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
    }
    return false;
}

<input type="text" onkeypress="alert(isCharacterKeyPress(event))">
Tim Down avatar Nov 15 '2010 01:11 Tim Down

Aquí hay una solución mucho más simple que funcionó bien para mí:

document.addEventListener('keyup', event => {
  if (String.fromCharCode(event.keyCode).match(/(\w|\s)/g)) {
    //pressed key is a char
  } else {
    //pressed key is a non-char
    //e.g. 'esc', 'backspace', 'up arrow'
  }
});
Expandir fragmento

Esto no requiere sondear un elemento DOM (lo que agregaría latencia y fealdad).

Uso de ejemplo actualizado:

mike-shtil avatar Mar 12 '2017 09:03 mike-shtil

La posible solución que puedo encontrar es verificar la longitud de la clave en el evento.

P.ej:-

<input type="text" id="testId" onkeyup="keyChecking(event)" />

<script type="text/javascript">
function keyChecking(event) {

    if (event.key.length == 1) {
        alert("key produced character " + event.key);
    } else {
        alert("Key DOES NOT produce character");

        const alphabets = "AZaz09";
        const key = event.key;
        var notEvenASymbol = false;

        for (let i = 0; i < key.length; i++) {
            var charCode = key.charCodeAt(i);
            if ((charCode >= alphabets.charCodeAt(0) && charCode <= alphabets.charCodeAt(1)) ||
                (charCode >= alphabets.charCodeAt(2) && charCode <= alphabets.charCodeAt(3)) ||
                (charCode >= alphabets.charCodeAt(4) && charCode <= alphabets.charCodeAt(5))
            ) {
                notEvenASymbol = true;
                console.log(charCode);
                break;
            }
        }

        if (notEvenASymbol) {
            alert("Key DOES NOT produce even a symbol");
        }
        console.log(event.key);

    }
}    
</script>

Entonces, si presiona algún carácter/símbolo, contendrá event.keyese carácter y su longitud será 1. Si presiona el carácter V , entonces event.keytendrá el valor V , pero si presiona la tecla Intro, contendrá el valor Enter , si presiona Mayús. luego Shift y así sucesivamente. Por lo tanto, si una clave no produce un carácter, su longitud será mayor que 1.

Actualizado

Algunas teclas especiales del teclado producen un símbolo y su longitud puede ser mayor que 1, así que modifiqué el código para que pueda alertar incluso si no es un símbolo. Por ejemplo: - 😄 su longitud es 2. Algunos teclados móviles tienen teclas de método abreviado para dichos símbolos.

Una tecla que no sea un carácter/símbolo en el teclado siempre será una combinación de alfabetos, caracteres numéricos o ambos, por ejemplo: F2 , Shift .

Gracias @Vicky Chijwani por llamar la atención sobre este escenario.

Visruth avatar Dec 02 '2016 12:12 Visruth

Para detectar en un keydowncontrolador si una tecla presionada produce un único carácter Unicode, puede usar el uindicador Unicode de ES6 para expresiones regulares.

Usamos la propiedad KeyboardEvent.key , que devuelve el valor de la tecla presionada. Según los documentos:

Si la tecla presionada tiene una representación impresa, el valor devuelto es una cadena de caracteres Unicode no vacía que contiene la representación imprimible de la clave.

inputElement.addEventListener("keydown", ({ key }) => {
  if (/^.$/u.test(key)) {
    // `key` matches a single unicode character
  }
});

La solución no soporta pegar...

valentin avatar Jun 20 '2020 19:06 valentin