How to clean up keyDown array - javascript

I'm fiddling around trying to build a game, and added some even listeners to find out which keys are down. I stack 'm up into one array, and use that array to manipulate the game-state.
If this is the wrong way to go about it, feel free to comment on that specifically, but I'm just going to assume for a moment that this is one of the ways to Rome.
My question; when someone presses multiple keys at once (or lots of them in the case of PS2 boards) these case might get "stuck" in the array, while not being down.
How would one prune this array, without removing keys that are actually down at that very moment?
var keysDown = []; // this is where I toss all they keyCodes
function keyDown(e) {
e = e || event;
if (keysDown.indexOf(e.keyCode) < 0) {
keysDown.push(e.keyCode)
console.log(keysDown);
};
};
function keyUp(e) {
e = e || event;
if (keysDown.indexOf(e.keyCode) > -1) {
keysDown.splice(keysDown.indexOf(e.keyCode), 1);
console.log(keysDown);
};
};
document.onkeydown = keyDown;
document.onkeyup = keyUp;
.edit: Fiddled it.

It looks like, with JS this just isn't possible.
The neatest way to handle this is to do nothing.
Alternatively you can consider keeping track of the total number of keys punched in and if it exceeds a certain number (hard to say how many) you could delete the first pressed keys, but that's more like patching a leaking barrel with some tape.

Related

Why wont this event listener work for multiple keys when in an array in javascript?

First code--> My first example does not work, and I am not sure why. I would say a condition, like if(keys[38]) where 38 in the example would be the event.keyCode. If true, it should execute the if statement.
second code--> The second example only works when there is one key being pushed, and I am not sure why it does not work for multiple keys, either. For multiple keys I would say something like if(keys[38] && keys[40]), but that will not work, it should be noted, however, that it would work for just one key, like just if(keys[38]).
I know that there are other ways to get this to work, but my objective is to figure out why these code pieces do not work.
first code piece:
var keys = [];
addEventListener("keydown", function(event) {
keys[event.keyCode] = event.type == "keydown";
event.preventDefault();
});
/*conditions*/
second code piece:
var keys = [];
addEventListener("keydown", function(event) {
keys[event.keyCode] = event.type == "keydown";
event.preventDefault();
/* conditions with multiple keys accessing by if(keys[38] && keys[40]*/
});
thanks ahead of time :)
When you press multiple keys, your addEventListener no longer listens to your first keypress. That's why your if statement is failing. You can test that out on the first example on http://api.jquery.com/event.which/ Try holding one key, then holding a second key, and then releasing the second key. You'll notice that the first key won't be logged anymore.
*edit: A way around that would be to implement it like this:
var keys = {};
$(document).keydown(function (e) {
keys[e.which] = true;
});
$(document).keyup(function (e) {
delete keys[e.which];
});
The difference is that in this case, nothing is getting overwritten, where as in your example your first key press is getting overwritten (and no longer saved) by the second key press.

How can I catch 2+ key presses at once?

Well lately i got interested in creating JS games. (not an area i have experience with but it interests me).
i know there are several gaming engines for JS out there but i dont really want to create a game. rather i am curious on how things work / how can i create one.
I have several questions:
Anyone with suggestions on where can I read about it? Prerequisite (what knowledge is needed).
I tried making a small game of something walking in a rectangular. By binding keyup to the window and checking the event.which to get the key that was pressed. I realized that if i clicked on 2 buttons same time only 1 of them is being registered. how can i overcome that?
$(window).keyup(function(event){
globalEvent = event.which;
});
To directly answer your second question.
Here is one way:
var keyPressed = {};
$(window).keydown(function(e) {
keyPressed[e.which] = true;
}).keyup(function(e) {
keyPressed[e.which] = false;
});
Now you can use keyPressed whenever you want to determine if a key is down:
// wherever
var key1 = 65, key2 = 66; // A and B
if (keyPressed[key1] && keyPressed[key2]) {
// A and B are both being pressed.
}
In order to detect multiple keys being held down, use the keydown and keyup events.
var keys = {};
$(document).keydown(function (e) {
keys[e.which] = true;
});
$(document).keyup(function (e) {
delete keys[e.which];
});

Cross-browser way to get automatically repeating keydown events when key is held down

Using Javascript / jQuery, how can I get automatically repeating keydown events, or equivalent, when someone holds down a key?
What I actually want is to be able to check whether a key is down, but from other questions here it looks like that's not possible. The suggested workaround seems to be recording keydown and keyup events and then assuming the key is down if a keydown event has been recorded and no subsequent keyup.
That solution runs into a problem in my case. I am designing an online experiment. The user is supposed to hold down the "T" key for the entire experiment, never letting it up. The experiment consists of multiple trials and each trial has no access to information recorded by the previous trials. So, trial 1 could record keydown for T, but trial 2 wouldn't have access to that record and thus wouldn't know whether T was down or not.
Now, if holding down the T key would produce automatically repeating keydown events for T, I would have no problem because trial 2 would just catch the next keydown event for T to come along. But it looks like I don't get automatically repeating keydown events from holding the key down, at least in Firefox. From what I can see it seems there is variation in the way different browsers handle holding a key down. What is a good cross-browser way to solve my problem?
By the way, if it matters, I also need to be able to detect keyup and keydown events for other keys while all this is going on.
EDIT: after reading some of the comments I went back and verified that I do indeed get repeating keydown events under ordinary circumstances. But I really don't get them in the specific situation in which I need them. I've got some simple code which I think isolates the issue:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<div id="target"></div>
</body>
<script type="text/javascript">
var i;
function foo() {
i++;
$('#target').html(i);
}
function doTrial() { // do trial
i=0;
$(document).keydown(foo);
$(document).keyup(endTrial);
}
function endTrial() { // end trial
$('#target').html('');
$(document).unbind('keydown',foo);
$(document).unbind('keyup',endTrial);
doTrial();
}
doTrial();
</script>
</html>
If you press a key and hold it down, then release, then press again, the behavior is as expected, i.e. there is a counter which increments while the key is held down, disappears when it's released, and then starts incrementing again when it's pressed again.
But if you press TWO keys down, then release ONE, I would have thought that the other (not released) key would continue sending keydown events so that the counter would (after resetting) continue incrementing. In fact, that doesn't happen. Any idea why and how to make it happen?
In the browsers I tried this in, I got repeated keydown events when holding a typeable key down. I don't know if this is a problem you actually need to solve.
But, if you did think you need to solve it OR if you want to control the repeat-rate yourself, you could do it like this:
Capture the events for keydown and keyup.
On keydown, set an interval timer that fires however often you want to know that the key is still down.
On keyup for that key, stop the interval timer.
You will get repeated notification in a cross browser way as long as the key is held down.
Working demo here: http://jsfiddle.net/jfriend00/XbZYs/
var downTimer;
var lastKey;
$(document.body).keydown(function(e) {
// if not still the same key, stop the timer
if (e.which !== lastKey) {
if (downTimer) {
clearInterval(downTimer);
downTimer = null;
}
}
// remember previous key
lastKey = e.which;
if (!downTimer) {
// start timer
downTimer = setInterval(function() {
$("#result").append("+");
}, 125);
}
}).keyup(function(e) {
// stop timer
if (downTimer) {
clearInterval(downTimer);
downTimer = null;
lastKey = 0;
}
});
If you want a key to auto-repeat forever until it is raised, even if other keys are pressed and released in the meantime and you want those other keys to do their own auto-repeating, then the OS does not ipmlement that behavior so you would have to implement it yourself. You can do something like this which calls a callback function for every key repeat event:
Working demo: http://jsfiddle.net/jfriend00/aD3Eg/
// this is called for every manufactured repeat event
// the frequency of the repeat event is determined by the time value set
// on setInterval() below
function repeatCallback(key) {
$("#result").append(key + " ");
}
var repeatState = {};
$(document.body).keydown(function(e) {
var key = e.which;
// if no time yet for this key, then start one
if (!repeatState[key]) {
// make copy of key code because `e` gets reused
// by other events in IE so it won't be preserved
repeatState[key] = setInterval(function() {
repeatCallback(key);
}, 125);
} else {
// nothing really to do here
// The key was pressed, but there is already a timer
// firing for it
}
}).keyup(function(e) {
// if we have a timer for this key, then stop it
// and delete it from the repeatState object
var key = e.which;
var timer = repeatState[key];
if (timer) {
clearInterval(timer);
delete repeatState[key];
}
});
​
The repeatCallback function is called for all of these manufactured auto-repeat events and passed the key that is auto-repeating. ​
Take a look at this jQuery plugin: fastKeys I think, that it is what you want/need...

Javascript dynamic Array not working

I am currently designing a function for website owners to track what is most commonly searched/entered on their website. To do this I have got a basic function recording what keys are pressed though I want to push these letters into an array so it is easier to manage but I am encountering a problem, it only pushes the last key entered into the array. I am new to programming so go easy on my code :P
Here is the code with the malfunctioning dynamic array:
$(document).ready(function() {
$(document).keyup(function(objEvent) {
(objEvent) ? keyCode = objEvent.keyCode : keyCode = event.keyCode;
varArray = [];
varLetter = String.fromCharCode(keyCode);
console.log(varLetter);
varArray.push(varLetter);
});
});
Thanks in advance
-Alex
You are resetting the array with every key press on this line...
varArray = [];
Declare and initialize your array outside of the event handler so it can accumulate keypresses rather than get reset every time. Your current code is setting the array back to be empty on every keypress with varArray = [];.
You can use something like this where varArray is declared and initialized once as a global variable. I also changed varLetter to be a local variable since it is only used locally and there is no need for it to be global:
var varArray = [];
$(document).ready(function() {
$(document).keyup(function(objEvent) {
(objEvent) ? keyCode = objEvent.keyCode : keyCode = event.keyCode;
var varLetter = String.fromCharCode(keyCode);
console.log(varLetter);
varArray.push(varLetter);
});
});

Javascript : How to get the last two characters typed into a textarea?

What is the best way to grab the last two characters typed into a textarea box?
I need the last 2 characters typed NOT the last two characters of the overall string.
Appreciate the help!
You need to catch the keypress event on the textarea and then keep a log of keys that were pressed. Note that this is going to catch arrow keys, shift, alt, etc so if you just want characters you need to filter them out.
Simple example:
var keyPresses = [];
textarea.onkeypress = function(ev){
ev = ev || window.event;
var key = ev.keyCode || ev.which;
keyPresses.push(key);
}
Here's a demo of doing it with jQuery, while displaying the last two characters that were entered: http://jsfiddle.net/Ender/5gUHb/
And the source:
var keys = [];
$('#target').keypress(function(e) {
keys.unshift(e.which);
update();
});
function update() {
$('#last')
.prepend($('<li/>').text(String.fromCharCode(keys[0])))
.children(':eq(2)').remove();
}
This demo captures the keypress event on the text area, unshifts the value onto the array (because then the indexes are representative of the number of keys that have been pressed since that key was pressed) and then updates the display.
The display update simply pushes the first value from the array to the top of a <ul> and removes the child (if any) at index 2 in the list.
Note additionally that because of the way jQuery deals with .keypress(), you do NOT have to filter out modifier or arrow keys.
UPDATE
Please see Tim Down's comment to my answer for an explanation of what filtering should take place. My initial note was mistaken, based on a quick test in Chrome.

Categories