Currently I have it set to "if true == true" just to simplify because the problem isn't there.
switchBoxes(player){
if (true == true){
document.addEventListener("keypress", function switchListen(event) {
if (event.keyCode == 101) {
console.log("TrapActivated");
}
}, {once:true});
}
}
I have a problem in my game that I am making in javascript where I see "TrapActivated" hundreds of times in the console when I only press the key 'E' once. switchBoxes is a function in a class called collisionObjects. It is meant to create a box that acts as a switch and effects some other part of the map I created when you press the key 'E'. The player is able to move around the map freely around the canvas. Instead of "if true == true", I had collision detection for the player to see if he was touching the switch. The parameter 'player' is so that you can choose who is able to use that switch. When I press 'E', the console gives me anywhere from around 34 to 500 messages. It stops very soon after I have pressed 'E', around 100-200 milliseconds later. And I haven't done anything with the framerate, so it should be whatever the default is.
This is my first question on this site so please forgive me if it is not as specific as it should be.
First of all, use event.key instead of event.keyCode;
Second - Your switchBoxes() function create new listener on every call;
So it's absolutely correct behaviour. For avoid this You can try to use removeEventListener. But, in My opinion, the best way in this case - declarate switchListen in parent scope. Something like:
function switchListen(event) {
if (event.key === 'e') {
console.log("TrapActivated");
}
}
function switchBoxes(player){
if (true == true){
document.addEventListener('keypress', switchListen, {once:true});
}
}
So, You'll create the only one listener, that will be removed at first call because of once:true;
Related
I have a ruby on rails application where the user can go to a previous or next question using their keyboard. One page is loaded at a time, which contains the link to a previous page, and the next page.
What I want to do is that if the user is at the very first page, pressing the left keyboard arrow key should not work at all, since it will be undefined. Additionally, if the user is at the very last page, pressing the right keyboard arrow key should not work either, since the next page will be undefined. Right now, if the user is at the first or last page and presses the left or right arrow key respectively, it throws an error in my application saying that "undefined" url can not be found.
I got the prev/next functionality working, but now am confused on how to proceed.
$(function() {
$(document).keyup(function(e) {
switch(e.keyCode) {
case 37 :
var a_href = $(this).find('a.previous_page').attr('href');
window.location=a_href;
break;
case 39 :
//window.location="/page-link-next";
var a_href = $(this).find('a.next_page').attr('href');
window.location=a_href;
break;
}
});
});
Use .length on a jQuery collection (such as .find) to figure out how many elements are in the collection.
Another thing to keep in mind is that var gets hoisted; having two vars declaring the same variable name inside a function isn't exactly valid. Better to declare the variable name elsewhere (such as at the top) and reassign, or use something other than a switch statement so you can use const, which has block scope and is a lot easier to deal with:
$(function() {
$(document).keyup(function(e) {
const keyCode = e.keyCode;
if (keyCode === 37) {
const a = $(this).find('a.previous_page');
if (a.length === 0) return;
window.location= a.attr('href');
} else if (keyCode === 39) {
const a = $(this).find('a.next_page');
if (a.length === 0) return;
window.location= a.attr('href');
}
});
});
It's better not to use switch if you can avoid it - it's unnecessarily wordy and error-prone.
I am trying to make a game where the right combination of numbers gives the player an effect to help them pass the level. My plan for doing this was using if statements to test for the key being pressed and change variables accordingly. This should be very simple, but my attempts have failed miserably, while I cannot find any pages that adequately explain this. So, does anyone know how I can detect the press of a number key for an if statement in javascript?
If what you are looking for is to enter some particular sequence of numbers, you'll need to use a cache and check each keystroke. Here is an example below. I have indicated that I want 1, then 2, then 3 in that order. Doing it wrong resets the sequence. Completing it also, in this case resets too.
Try it out. run it and pres 1, then 2 then 3. Interrupting the sequence means you must restart.
//press 1, then 2 then 3
var code = [49, 50, 51]
var cache = [];
function checkCode(eve) {
var keycode = eve.keyCode || eve.which;
if(keycode === cache.shift()){
if(!cache.length){
//resets if you did it. do not include if you want once.
replenishCache();
//do whatever you do here.
doThing();
}
} else {
replenishCache();
}
}
function doThing(){
alert('sequence entered');
}
function replenishCache(){
cache = code.slice(0);
}
replenishCache();
window.addEventListener('keypress', checkCode, false);
I will add that this code is totally not in the context of any framework, or module or pattern. I just attached an event to window to illustrate. You'll need to think about how to migrate this into whatever you are doing. For example, rather than just calling a more global function directly doThing in this case - you should probably pass that into some sort of plugin or module. Same thing with the sequence of character codes.
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...
I need to fire an event anytime the content of a textbox has changed.
I cant use keyup nor can I use keypress.
Keyup and keydown doesn't work if you hold down on the key.
Keypress triggers before the text has actually changed. It doesn't recognize backspace or delete either.
So now I'm assuming I'm going to have to build some custom logic or download a plugin. Are there any plugins out there? Or if I should build one, what constraints should I look out for?
For eg. Facebook does it with their search at the top. you can press and hold.
another example is writing a stackoverflow question. Right below the editor, the contents are copied in real time, backspace and everythng works. How do they do it?
I just took a look at SO's source. It looks like they do something a lot like this:
function updatePreview(){
$('div').text($('textarea').val());
}
$('textarea').bind('keypress', function(){
setTimeout(updatePreview, 1);
}
);
They do some extra stuff to make HTML tags for bold and italics and links and such and they time it. They increase the delay from 1 to longer if it takes too long to generate the HTML.
I had success using jQuery (in Chrome). If you hold a key down, it counts every change, not just the first one, and it counts non-print keys like backspace.
HTML
<input id="txt" type="text" />
<span id="changeCount">0</span>
JavaScript
$('#txt').keydown(function(event) {
// Don't count the keys which don't actually change
// the text. The four below are the arrow keys, but
// there are more that I omitted for brevity.
if (event.which != 37 && event.which != 38 &&
event.which != 39 && event.which != 40) {
// Replace the two lines below with whatever you want to
// do when the text changes.
var count = parseInt($('#changeCount').text(), 10) + 1;
$('#changeCount').text(count);
}
});
Like I said above, you'll want to filter out all of the key codes that don't change the text, like ctrl, shift, alt, enter, etc. There's also the boundary condition if you press the backspace or delete key when the textbox is empty or if the textbox has a maximum length and a printable key is pressed, but it's not terribly difficult to handle those either.
Here's a working jsfiddle example.
How about a poll? Do a setInterval and call a function that checks the text say every 500ms? You don't want to detect content change on every key anyway because it gets kinda slow in some older browser/older computer and you would notice a lag between typing and the text displaying.
You need a watcher type functionality.
It resorts to setInterval polling if the other features are not available: http://james.padolsey.com/javascript/monitoring-dom-properties/
I have a simple solution that we use happily in one of our project.
you can try it # http://jsfiddle.net/zSFdp/17/
var i = 0;
$('#text').bind('check_changed', function(){
var t = $(this);
// do something after certain interval, for better performance
delayRun('my_text', function(){
var pv = t.data('prev_val');
// if previous value is undefined or not equals to the current value then blablabla
if(pv == undefined || pv != t.val()){
$('#count').html(++i);
t.data('prev_val', t.val());
}
}, 1000);
})
// if the textbox is changed via typing
.keydown(function(){$(this).trigger('check_changed')})
// if the textbox is changed via 'paste' action from mouse context menu
.bind('paste', function(){$(this).trigger('check_changed')});
// clicking the flush button can force all pending functions to be run immediately
// e.g., if you want to submit the form, all delayed functions or validations should be called before submitting.
// delayRun.flush() is the method for this purpose
$('#flush').click(function(){ delayRun.flush(); });
The delayRun() function
;(function(g){
var delayRuns = {};
var allFuncs = {};
g.delayRun = function(id, func, delay){
if(delay == undefined) delay = 200;
if(delayRuns[id] != null){
clearTimeout(delayRuns[id]);
delete delayRuns[id];
delete allFuncs[id];
}
allFuncs[id] = func;
delayRuns[id] = setTimeout(function(){
func();
delete allFuncs[id];
delete delayRuns[id];
}, delay);
};
g.delayRun.flush = function(){
for(var i in delayRuns){
if(delayRuns.hasOwnProperty(i)){
clearTimeout(delayRuns[i]);
allFuncs[i]();
delete delayRuns[i];
delete allFuncs[i];
}
}
};
})(window);
Zurb has a great plugin which might be useful for you
http://www.zurb.com/playground/jquery-text-change-custom-event
To polish up an application im developing I am adding keyboard shortcuts for common tasks. I can sue Ext.KeyMap to do this like so...
var map = new Ext.KeyMap("my-element", {
key: 13, // or Ext.EventObject.ENTER
fn: myHandler,
scope: myObject
});
But I want to detect "ss" or "qq" i.e. specific double key strokes of letters. Im not sure how to do this....
My idea is to detect the singular keystroke, add a listener to detect a following key stroke. And to handle the gap between them, set a delayed event that deletes the listener after x amount of time.
Any improvements/suggestions/warnings??
I'm not sure why you would need an additional listener here. Why not store the previous keystroke in a variable (with the timestamp when the keystroke occurred). Then you could just compare the latest keystroke to the previous keystroke. If they are the same, and the timestamp stored is not too far in the past, that's the double key you're after. If the key codes are not the same, or stored timestamp is too old, just update the stored keycode and timestamp with new values.
You don't have to remember all the keys pressed, just the last one. When you think at the double click event, it's similar, but since clicking two times is more popular, it's already implemented for us.
Something like this:
function defineDoubleKeyMap(element, cfg) {
var repeated, timer;
return new Ext.KeyMap(element, {
key: cfg.key,
fn: function() {
if (repeated) {
// when clicked the second time
// stop timer and call our callback
repeated = false;
clearTimeout(timer);
cfg.fn.call(cfg.scope);
}
else {
// remember we clicked once, forget after delay
repeated = true;
// adjust the delay as needed.
// current 1 sec is probably too long
timer = (function(){
repeated = false;
}).defer(1000);
}
}
});
}
defineDoubleKeyMap("my-element", {
key: Ext.EventObject.ENTER,
fn: myHandle,
scope: myObject
});
The probem with this code is that pressing quickly ENTER-DELETE-ENTER will also fire the event as if ENTER-ENTER was pressed. If that's not acceptable, then you have to keep track of all the keypresses - I think you'll have to use Ext.get("my-element").on("keypress") for that.