I don't know why this appears to be so difficult to figure out. I want to be able to execute code when a key is pressed and held but only once. Instead when I use onkeypress or onkeydown the function that I bound gets executed repeatedly which is not what I want. How can I have the handler be executed just once when the key is held down?
Note: I don't want to embed logic into the function that will limit its execution, I want it not to be firing the event more than once no matter how long I hold the key.
EDIT I
Here is the demo and the code
HTML
<div id="counter">0</div>
JS
var counter = 0,
div = document.getElementById('counter');
document.body.onkeypress = function(){
div.innerHTML = counter++;
}
Notice how when you press and hold any key the counter keeps going, I want it to count just once no matter how long I hold the key, and keep in mind the notice from above.
EDIT II
Sorry forgot to mention removing the listener is not acceptable, I need to increase the counter by 1 every time a key is pressed but no matter how long it's held.
You do have to use logic to avoid repetitive events on a key being pressed, because there's no specific and compatible event for key being just pressed.
More specifically, the easiest solution is to store a boolean, setting it true on key up, false on key down (after having done your action), and ignoring the key down event while it's false:
(function(){
var shouldHandleKeyDown = true;
document.onkeydown = function(){
if (!shouldHandleKeyDown) return;
shouldHandleKeyDown = false;
// HANDLE KEY DOWN HERE
}
document.onkeyup = function(){
shouldHandleKeyDown = true;
}
})();
Demonstration
EDIT for 2019
Now that IE is dead, you can also use the event.repeat property, which is true when the event is a repetition.
The easiest way to handle this is by using the repeat property in the event:
// I'd recommend using addEventListener instead, but
// this is as close to the original code as possible
document.body.onkeypress = function (event) {
if (!event.repeat) {
div.innerHTML = counter++;
}
}
event.repeat is false for the very first event, and true for repeated events (the ones that are fired when you hold down a key).
Another option is to use keyup, which is always only used once, since you can't "hold up" a key, so it's never repeated (but keyup is a bad choice for e.g. buttons, because it can break keyboard navigation compared to keypress).
JSFiddle: http://jsfiddle.net/ts7w58od/
1. Bind listener
2. Unbind when event is fire.
var element = document.getElementById('target'),
once = function () {
console.log('once');
element.removeEventListener('keypress', once);
};
element.addEventListener('keypress', once, false);
This is a modified version of Denys Séguret answer
let shouldHandleKeyDown = true;
let n = 0;
document.addEventListener('keydown', function() {
if (!shouldHandleKeyDown) return;
shouldHandleKeyDown = false;
document.getElementById('counter').innerHTML = ++n;
});
document.addEventListener('keyup', function () {
shouldHandleKeyDown = true;
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Counter</title>
</head>
<body>
Counter : <span id=counter>0</span>
</body>
</html>
Related
There is a button linked to a machine that sends a keypress to this app
Sometimes the button will "double tap" the key combination (Double shift + S)
Tried some of the responses over here: "How to trap double key press in javascript?"
as it seems along the lines of what I need but can't seem to get any to work
function myFunction(xml) {
// Start on keypress
document.addEventListener('keyup', function(e) {
if (e.keyCode == 83 && e.shiftKey)
// Set a baseline for first keypress to compare later
var lastKeypressTime = 0;
// Code to run after initial keypress here
// Basically a bunch of TTS reading from XML until either it finishes, or a button is pressed for a reload
// I think this is kind of along the lines of what I'm after but can't quite implement it properly
// Detect the keypress
document.addEventListener('keyup', function(e) {
if (e.keyCode == 83 && e.shiftKey)
// Set time of keypress to compare
var thisKeypressTime = new Date();
// if time between first keypress is greater than 2 seconds, let the page reload
if (thisKeypressTime - lastKeypressTime >= 2000)
window.location.reload();
else
// Otherwise, ignore all keypresses until the 2 seconds (at least) has passed before the button press works again
})
})
}
Due to the button being... imperfect.. When it registers a single press as a double press, the page is reloaded instantly
Basically needing either the first keypress that "starts" the TTS to never register a faulty double press, or have any consecutive keypress ignored entirely until after a certain period has passed or something to that extent
Any guidance or alternatives to what I'm trying to accomplish would be greatly appreciated :)
const delta = 1500;
let lastPress = 0;
function handleKeyPress(event) {
let currentPress = new Date();
if (event.key === "S" && event.shiftKey) {
if (currentPress - lastPress <= delta) {
alert("Shift + s");
currentPress = 0;
}
lastPress = currentPress;
}
}
document.addEventListener("keyup", handleKeyPress);
This is a snippet that works, you have to define the lastPress variable outside your function, and I don't understand why you're trying to register two listeners for the keyup event. Once that you've defined your listener handler, it will be called every time the event that you're listening on is fired; this is why you have to save the lastPress and the currentPress times.
P.S.
Obviously instead of alert something on the double keypress you can run your own function.
Instead of detecting when a key is down, how do I detect if a key is released?
One option is to use onUpCallback. For example, in your create function add something like the following:
game.input.keyboard.onUpCallback = function (e) {
// These can be checked against Phaser.Keyboard.UP, for example.
console.log(e.keyCode);
};
I suppose you could also store whether the key is down in your update function, and then check on each iteration whether it's up, if you wanted to keep track of the amount of time the key were pressed down.
I'm not sure what sort of performance issues you would run into though, so I would probably start with onUpCallback.
Set a flag when the key is pressed. In the update loop check if the flag is set but the key is no longer down:
//... somewhere
var downFlag = false;
//... in update
if(yourkey.isDown){
downFlag = true;
}else{
if(downFlag){
downFlag = false;
//do something
}
}
..but start with what James says
In the code below, instead of using on keydown, is there a way I can use on e.which === 13 where the keydown is? This was it wont have to check each time a key is pressed, and will work only when enter is pressed.
Current Code
$('.search').on('keydown', function(e) {
if(e.which === 13) {
// enter key pressed
var value = this.value; // this is the inputs value
console.log(value);
}
});
What I hope to do (pseudo code)
$('.search').(when key === 13 is pressed) { // Only if the enter key pressed
// enter key pressed
var value = this.value; // this is the inputs value
console.log(value);
}
});
Can something like this be done?
You could use a higher-order function to extract that logic for you:
function onlyOnEnter(fn) {
return function(e) {
if(e.which === 13) {
fn.apply(this, arguments);
}
}
}
Usage:
$('.search').on('keydown', onlyOnEnter(function(e) {
var value = this.value; // this is the inputs value
console.log(value);
})
);
That way, your callback function will only be called when the key pressed is an enter.
Not really.
The best you can do is capturing events (you are using on but it could be any other event capturing method). There are many different kind of events (mouse events, keyboard events, control specific events, etc.), you have to look at the event, since each event type will have different properties.
For key pressing, there are some events available for capturing such as keypress, keydown and keyup. You can't expect that one specific key will have an event on its own because you want so save one line of code.
No, this isn't really possible (at least not for the purposes of your code) nor does it make a lot of sense. The keydown event is fired whenever a key is pressed.
Whether you are manually checking to see if it's the enter key or whether the browser or jQuery is doing it internally isn't tremendously relevant - regardless the browser will need to check which key was pressed any time any key is pressed to test whether it was the enter key.
Essentially you're wasting your time. There isn't going to be any measurable performance optimization by trying to do this. No matter how you try to detect the enter key being pressed, it will be tested for every keydown or keypress event regardless of which key is pressed.
im creating a simple 2d game, and I want save the keydown keys into array, and execute them inisde a loop, so the user can hold a key and make it look like the chartater is moving non stop.
i got a setInterval function that act like a game Timer, and it just loop it self all the time. i added a listener and an array to hold the key.
I checked the keys inside the array and it look fine but, the functions moveRight and moveLeft are not working for some reson.
here is the code:
this.keysPressed = new Array();
InitGameLoop: function () {
var that = this;
setInterval(function () {
$(document).keydown(function (e) {
var key = e.which;
that.keysPressed.push(key);
for (var i = 0; i < that.keysPressed.length; i++) {
if (that.keysPressed[i] == 38) {
that.moveRight(worldWidth, 10);
}
else if (that.keysPressed[i] == 37) {
that.moveLeft(10);
}
log(that.keysPressed, that.yPos);
that.keysPressed.pop();
}
});
}, 60);
my questions are:
what am i doing worng?
is this a good idea? (if not, please feel free to recommend me about another :) )
(sorry for my english)
Registering an eventhandler inside setInterval is always wrong. In your case, every 60 milliseconds you are creating an additional listener, and when you press a key, all of your listeners will fire. Also there is absolutely no need to store them in an array. Just register the listener once, and it will fire each time a key is pressed. If more than one keys are pressed, the listener will fire for each key individually.
$(document).keydown(function (e) {
var key = e.which;
console.log(key);
// call your according functions here
switch (key){
case 37: // moving left
// do stuff
// set a flag to indicate that you are moving left
moveleft = true;
break;
case 39: // moving right
// do stuff
// set a flag to indicate that you are moving right
moveright = true;
break;
}
});
Since you are catching the keydown, you should set flags. This way you can track which keys are pressed currently. On keyup, you are resetting these flags again (need another eventhandler for that).
Instead of storing the pressed keys in an array, make each key code activate a related var in a 'movement' array. e.g. when left is pressed, movement['left']=1. Use keyup to set it back to 0.
Have your loop check the array for each possible movement, and trigger the related functions in corelance to the active movements at that given moment.
I'm writing a platform game for my university project using the canvas element and Javascript. I'm well on my way, but I'm stuck at how to see if a certain key is being pressed in my players update loop.
I was thinking like this:
if(d) {
// move player right
} else if(a) {
// move player left
} else if(w) {
// move player up
} else if(s) {
// move player down
}
That's psudocode, obviously. The only resources to key presses in Javascript that I can find are events, nothing to see if a key is being pressed at a certain point.
Can anyone shed some light on this?
Setup 4 boolean variables if key is up or down. On keydown set it to true, on keyup set it to false. Than you can do if(key_d == true) { // key d is pressed }
That's the best way to do it. Its not "hacky", add event listeners to handle key presses.
I don't think you can get around using keydown, keyup, or keypress for determining which keys are pressed. However, instead of running this code within one of those event handlers, you could set and unset some global flag within them. Then, when this code runs (I'm assuming it'll be on some kind of interval?), it could check for the flag.
You need an event listener.
//function foo, returns keypress
function foo(e){
var evt=(e)?e:(window.event)?window.event:null;
if(evt){
var key=(evt.charCode)?evt.charCode:
((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
return key;
}
//set event listener
//you could also attach this to your canvas, but that will require tricks
//to make the canvas focusable
document.addEventListener('keydown', foo);