español ejemplos descargar definicion curso caracteristicas javascript

ejemplos - JavaScript múltiples teclas presionadas a la vez



javascript html (9)

Estoy tratando de desarrollar un motor de juegos de JavaScript y me he encontrado con este problema:

Cuando presiono espacio, el personaje salta. Cuando presiono la flecha derecha, el personaje se mueve hacia la derecha.

El problema es que cuando sigo presionando, presiono el espacio, el personaje salta y deja de moverse.

Uso la función de teclado para presionar la tecla, ¿cómo puedo verificar si hay varias teclas presionadas?


Debe usar el evento de selección para realizar un seguimiento de las teclas presionadas, y debe usar el evento de activación para realizar un seguimiento de cuándo se liberan las claves.

Ver este ejemplo: http://jsfiddle.net/vor0nwe/mkHsU/

(Actualización: estoy reproduciendo el código aquí, en caso de que jsfiddle.net renuncie :) El HTML:

<ul id="log"> <li>List of keys:</li> </ul>

... y el Javascript (usando jQuery):

var log = $(''#log'')[0], pressedKeys = []; $(document.body).keydown(function (evt) { var li = pressedKeys[evt.keyCode]; if (!li) { li = log.appendChild(document.createElement(''li'')); pressedKeys[evt.keyCode] = li; } $(li).text(''Down: '' + evt.keyCode); $(li).removeClass(''key-up''); }); $(document.body).keyup(function (evt) { var li = pressedKeys[evt.keyCode]; if (!li) { li = log.appendChild(document.createElement(''li'')); } $(li).text(''Up: '' + evt.keyCode); $(li).addClass(''key-up''); });

En ese ejemplo, estoy usando una matriz para realizar un seguimiento de las teclas que se están presionando. En una aplicación real, es posible que desee delete cada elemento una vez que se haya liberado su clave asociada.

Tenga en cuenta que, si bien he utilizado jQuery para hacer las cosas más fáciles para mí en este ejemplo, el concepto funciona igual de bien cuando se trabaja en Javascript "en bruto".


Haga que la tecla incluso llame a funciones múltiples, con cada función comprobando una clave específica y respondiendo adecuadamente.

document.keydown = function (key) { checkKey("x"); checkKey("y"); };


Intentaría agregar un controlador de Event keypress al momento de la keydown . P.ej:

window.onkeydown = function() { // evaluate key and call respective handler window.onkeypress = function() { // evaluate key and call respective handler } } window.onkeyup = function() { window.onkeypress = void(0) ; }

Esto solo pretende ilustrar un patrón; No entraré en detalles aquí (especialmente no en el nivel específico del navegador2 + registro de Event ).

Publique por favor si esto ayuda o no.


La detección de pulsaciones múltiples es fácil si comprende el concepto

La forma en que lo hago es así:

var map = {}; // You could also use an array onkeydown = onkeyup = function(e){ e = e || event; // to deal with IE map[e.keyCode] = e.type == ''keydown''; /* insert conditional here */ }

Este código es muy simple: dado que la computadora solo pasa una pulsación de tecla a la vez, se crea una matriz para realizar un seguimiento de varias claves. La matriz se puede usar para verificar una o más claves a la vez.

Solo para explicar, digamos que presiona A y B , cada uno dispara un evento de keydown que establece el map[e.keyCode] en el valor de e.type == keydown , que se evalúa como verdadero o falso . Ahora tanto el map[65] como el map[66] se establecen en true . Cuando suelta A , el evento de keyup se dispara, provocando que la misma lógica determine el resultado opuesto para el map[65] (A), que ahora es falso , pero dado que el map[66] (B) aún está "abajo" ( no ha desencadenado un evento de tecla), sigue siendo cierto .

La matriz de map , a través de ambos eventos, se ve así:

// keydown A // keydown B [ 65:true, 66:true ] // keyup A // keydown B [ 65:false, 66:true ]

Hay dos cosas que puedes hacer ahora:

A) Se puede crear un registrador de claves ( example ) como referencia para más adelante cuando desee descubrir rápidamente uno o más códigos clave. Suponiendo que haya definido un elemento html y lo haya apuntado con el element variable.

element.innerHTML = ''''; var i, l = map.length; for(i = 0; i < l; i ++){ if(map[i]){ element.innerHTML += ''<hr>'' + i; } }

Nota: Puede agarrar fácilmente un elemento por su atributo id .

<div id="element"></div>

Esto crea un elemento html que se puede referenciar fácilmente en javascript con el element

alert(element); // [Object HTMLDivElement]

Ni siquiera tiene que usar document.getElementById() o $() para tomarlo. Pero por el bien de la compatibilidad, el uso de jQuery''s $() es más ampliamente recomendado.

Solo asegúrese de que la etiqueta del script venga después del cuerpo del HTML. Sugerencia de optimización : la mayoría de los sitios web de renombre ponen la etiqueta del script después de la etiqueta del cuerpo para la optimización. Esto se debe a que la etiqueta del script bloquea la carga de otros elementos hasta que se termina de descargar el script. Ponerlo por delante del contenido permite que el contenido se cargue de antemano.

B (que es donde reside su interés) Puede buscar una o más claves a la vez donde /*insert conditional here*/ era, tome este ejemplo:

if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A alert(''Control Shift A''); }else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B alert(''Control Shift B''); }else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C alert(''Control Shift C''); }

Editar : Ese no es el fragmento más legible. La legibilidad es importante, por lo que podría intentar algo como esto para que sea más fácil para los ojos:

function test_key(selkey){ var alias = { "ctrl": 17, "shift": 16, "A": 65, /* ... */ }; return key[selkey] || key[alias[selkey]]; } function test_keys(){ var keylist = arguments; for(var i = 0; i < keylist.length; i++) if(!test_key(keylist[i])) return false; return true; }

Uso:

test_keys(13, 16, 65) test_keys(''ctrl'', ''shift'', ''A'') test_key(65) test_key(''A'')

¿Es esto mejor?

if(test_keys(''ctrl'', ''shift'')){ if(test_key(''A'')){ alert(''Control Shift A''); } else if(test_key(''B'')){ alert(''Control Shift B''); } else if(test_key(''C'')){ alert(''Control Shift C''); } }

(fin de editar)

Este ejemplo busca Ctrl Shift A , Ctrl Shift B y Ctrl Shift C

Es tan simple como eso :)

Notas

Mantener un registro de KeyCodes

Como regla general, es una buena práctica documentar código, especialmente cosas como códigos clave (como // CTRL+ENTER ) para que pueda recordar cuáles fueron.

También debe colocar los códigos clave en el mismo orden que la documentación ( CTRL+ENTER => map[17] && map[13] , NO map[13] && map[17] ). De esta forma, nunca se confundirá cuando necesite regresar y editar el código.

Un gotcha con If-else cadenas

Si busca combos de diferentes cantidades (como Ctrl Shift Alt Enter y Ctrl Enter ), ponga combos más pequeños después de combos más grandes, o de lo contrario los combos más pequeños anularán los combos más grandes si son lo suficientemente similares. Ejemplo:

// Correct: if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER alert(''Whoa, mr. power user''); }else if(map[17] && map[13]){ // CTRL+ENTER alert(''You found me''); }else if(map[13]){ // ENTER alert(''You pressed Enter. You win the prize!'') } // Incorrect: if(map[17] && map[13]){ // CTRL+ENTER alert(''You found me''); }else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER alert(''Whoa, mr. power user''); }else if(map[13]){ // ENTER alert(''You pressed Enter. You win the prize!''); } // What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will // detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER. // Removing the else''s is not a proper solution, either // as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"

Gotcha: "Esta combinación de teclas se sigue activando a pesar de que no presiono las teclas"

Cuando se trata de alertas o cualquier cosa que toma el foco de la ventana principal, es posible que desee incluir map = [] para restablecer la matriz una vez que se complete la condición. Esto se debe a que algunas cosas, como alert() , quitan el foco de la ventana principal y hacen que el evento ''keyup'' no se dispare. Por ejemplo:

if(map[17] && map[13]){ // CTRL+ENTER alert(''Oh noes, a bug!''); } // When you Press any key after executing this, it will alert again, even though you // are clearly NOT pressing CTRL+ENTER // The fix would look like this: if(map[17] && map[13]){ // CTRL+ENTER alert(''Take that, bug!''); map = {}; } // The bug no longer happens since the array is cleared

Gotcha: Predeterminados del navegador

Aquí hay algo molesto que encontré, con la solución incluida:

Problema: como el navegador generalmente tiene acciones predeterminadas en combos de teclas (como Ctrl D activa la ventana del marcador, o Ctrl Shift C activa skynote en maxthon), también puede agregar return false after map = [] , para que los usuarios de su sitio no se frustrará cuando la función "Duplicar archivo", al estar en Ctrl D , marque la página en su lugar.

if(map[17] && map[68]){ // CTRL+D alert(''The bookmark window didn/'t pop up!''); map = {}; return false; }

Sin return false , la ventana de Marcador aparecería, para consternación del usuario.

La declaración de devolución (nueva)

De acuerdo, entonces no siempre quieres salir de la función en ese punto. Es por eso que la función event.preventDefault() está ahí. Lo que hace es establecer un indicador interno que le dice al intérprete que no permita que el navegador ejecute su acción predeterminada. Después de eso, la ejecución de la función continúa (mientras que el return saldrá inmediatamente de la función).

Comprenda esta distinción antes de decidir si usar return false o e.preventDefault()

event.keyCode está en desuso

El usuario SeanVieira señaló en los comentarios que event.keyCode está en desuso.

Allí, dio una excelente alternativa: event.key , que devuelve una representación de cadena de la tecla presionada, como "a" para A , o "Shift" para Shift .

Seguí adelante y preparé una tool para examinar dichas cadenas.

element.onevent vs element.addEventListener

Los manipuladores registrados con addEventListener se pueden apilar y se llaman en el orden de registro, mientras que configurar .onevent directamente es bastante agresivo y anula todo lo que tenía anteriormente.

document.body.onkeydown = function(ev){ // do some stuff ev.preventDefault(); // cancels default actions return false; // cancels this function as well as default actions } document.body.addEventListener("keydown", function(ev){ // do some stuff ev.preventDefault() // cancels default actions return false; // cancels this function only });

La propiedad .onevent parece anular todo y el comportamiento de ev.preventDefault() y return false; puede ser bastante impredecible

En cualquier caso, los controladores registrados a través de addEventlistener parecen ser más fáciles de escribir y razonar.

También hay attachEvent("onevent", callback) de la implementación no estándar de Internet Explorer, pero esto está más allá de la obsolescencia y ni siquiera se relaciona con JavaScript (pertenece a un lenguaje esotérico llamado JScript ). Le conviene evitar el código de políglota tanto como sea posible.

Una clase de ayuda

Para abordar la confusión / quejas, he escrito una "clase" que hace esta abstracción ( enlace pastebin ):

function Input(el){ var parent = el, map = {}, intervals = {}; function ev_kdown(ev) { map[ev.key] = true; ev.preventDefault(); return; } function ev_kup(ev) { map[ev.key] = false; ev.preventDefault(); return; } function key_down(key) { return map[key]; } function keys_down_array(array) { for(var i = 0; i < array.length; i++) if(!key_down(array[i])) return false; return true; } function keys_down_arguments() { return keys_down_array(Array.from(arguments)); } function clear() { map = {}; } function watch_loop(keylist, callback) { return function(){ if(keys_down_array(keylist)) callback(); } } function watch(name, callback) { var keylist = Array.from(arguments).splice(2); intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24); } function unwatch(name) { clearInterval(intervals[name]); delete intervals[name]; } function detach() { parent.removeEventListener("keydown", ev_kdown); parent.removeEventListener("keyup", ev_kup); } function attach() { parent.addEventListener("keydown", ev_kdown); parent.addEventListener("keyup", ev_kup); } function Input() { attach(); return { key_down: key_down, keys_down: keys_down_arguments, watch: watch, unwatch: unwatch, clear: clear, detach: detach }; } return Input(); }

Esta clase no hace todo y no manejará todos los casos de uso imaginables. No soy un tipo de biblioteca. Pero para un uso interactivo general, debería estar bien.

Para usar esta clase, crea una instancia y apúntala al elemento al que deseas asociar la entrada del teclado con:

var input_txt = Input(document.getElementById("txt")); input_txt.watch("print_5", function(){ txt.value += "FIVE "; }, "Control", "5");

Lo que esto hará es adjuntar un nuevo oyente de entrada al elemento con #txt (supongamos que es un área de texto), y establecer un punto de observación para la combinación de Ctrl+5 . Cuando tanto Ctrl como 5 están inactivos, se llamará a la función de devolución de llamada que ingresó (en este caso, una función que agrega "FIVE " al área de texto). La devolución de llamada está asociada con el nombre print_5 , por lo que para eliminarlo, simplemente utiliza:

input_txt.unwatch("print_5");

Para separar input_txt del elemento txt :

input_txt.detach();

De esta forma, la recolección de basura puede recoger el objeto ( input_txt ), en caso de que se input_txt , y no tendrá un viejo detector de eventos zombie.

Para mayor precisión, aquí hay una referencia rápida a la API de la clase, presentada en estilo C / Java para que sepa qué devuelven y qué argumentos esperan.

Boolean key_down (String key);

Devuelve true si la key está abajo, de lo contrario es falso.

Boolean keys_down (String key1, String key2, ...);

Devuelve true si todas las teclas key1 .. keyN están key1 .. keyN , de lo contrario, key1 .. keyN false.

void watch (String name, Function callback, String key1, String key2, ...);

Crea un "punto de keyN " tal que al presionar toda la tecla keyN se activará la devolución de llamada

void unwatch (String name);

Elimina dicho punto de observación a través de su nombre

void clear (void);

Limpia la memoria caché "keys down". Equivalente a map = {} anterior

void detach (void);

Separa los oyentes ev_kdown y ev_kup del elemento primario, lo que permite deshacerse de la instancia de forma segura

Actualización 2017-12-02 En respuesta a una solicitud para publicar esto en github, he creado una gist .

Espero que esta respuesta completamente explicada haya sido útil :)


Lo usé de esta manera (tuve que verificar dónde presioné Shift + Ctrl):

// create some object to save all pressed keys var keys = { shift: false, ctrl: false }; $(document.body).keydown(function(event) { // save status of the button ''pressed'' == ''true'' if (event.keyCode == 16) { keys["shift"] = true; } else if (event.keyCode == 17) { keys["ctrl"] = true; } if (keys["shift"] && keys["ctrl"]) { $("#convert").trigger("click"); // or do anything else } }); $(document.body).keyup(function(event) { // reset status of the button ''released'' == ''false'' if (event.keyCode == 16) { keys["shift"] = false; } else if (event.keyCode == 17) { keys["ctrl"] = false; } });


Si una de las teclas presionadas es Alt / Crtl / Shift puede usar este método:

document.body.addEventListener(''keydown'', keysDown(actions) ); function actions() { // do stuff here } // simultaneous pressing Alt + R function keysDown (cb) { return function (zEvent) { if (zEvent.altKey && zEvent.code === "KeyR" ) { return cb() } } }


para quién necesita el código de ejemplo completo. Derecha + izquierda añadidas

var keyPressed = {}; document.addEventListener(''keydown'', function(e) { keyPressed[e.key + e.location] = true; if(keyPressed.Shift1 == true && keyPressed.Control1 == true){ // Left shift+CONTROL pressed! keyPressed = {}; // reset key map } if(keyPressed.Shift2 == true && keyPressed.Control2 == true){ // Right shift+CONTROL pressed! keyPressed = {}; } }, false); document.addEventListener(''keyup'', function(e) { keyPressed[e.key + e.location] = false; keyPressed = {}; }, false);


case 65: //A jp = 1; setTimeout("jp = 0;", 100); if(pj > 0) { ABFunction(); pj = 0; } break; case 66: //B pj = 1; setTimeout("pj = 0;", 100); if(jp > 0) { ABFunction(); jp = 0; } break;

No es la mejor manera, lo sé.


document.onkeydown = keydown; function keydown (evt) { if (!evt) evt = event; if (evt.ctrlKey && evt.altKey && evt.keyCode === 115) { alert("CTRL+ALT+F4"); } else if (evt.shiftKey && evt.keyCode === 9) { alert("Shift+TAB"); } }