I'm working on my personal website and I've build in some easter egg hotkeys. On every page pressing the 'm' key should hide the menu and pressing the 'g' key should launch a game ontop of the current page. On another page I have the 't' and 'l' keys perform other CSS changes. On every page the game and menu keys operate as expected except for the page with the listener for 't' and 'l'. There is clearly some kind of conflict preventing them all from working on each page. I believe it is because I have the listeners declared across three different files. I would like to keep it that way so that my site is more modular (i.e. I can easily transfer the js file for the game to any other website). Any ideas?
First listener, 'm' key: (nav-script.js)
document.addEventListener('keydown', function(evt){
var evt = evt || window.event;
if(evt.keyCode == 77){
showNav();
}
},false);
Second listener, 'g' key: (clickgame.js)
document.onkeydown = enable;
function enable(event){
// Enables/disables the game
var event = event || window.event;
if(event.keyCode == 71 && !enabled){ // 71 is the code for the 'G' key
game = true;
enabled = true;
setup();
}else if(event.keyCode == 71){
game = false;
enabled = false;
quitgame();
}
}
Third listener, 'l' and 't' keys: (project-focus.js)
document.onkeydown = focusFeatures;
function focusFeatures(event){
var event = event || window.event;
if(event.keyCode == 76){
lightswitch();
}else if(event.keyCode == 84){
textswitch();
}
}
The document.onkeydown = assignment overwrites all previously assigned handlers. You need to use addListener to effectively attach multiple handlers for the same event.
Or, you could just use jQuery as that will make things a whole lot easier.
When you do this:
document.onkeydown = focusFeatures;
You are replacing every other onkeydown listener with focusFeatures.
This is the same for document.onkeydown = enable.
You should do this instead:
document.addEventListener('keydown', enable, false); // for the games
document.addEventListener('keydown', focusFeatures, false); // for the focus features
Plus you should first declare the function, and then assign it to the listener.
Am I correct in understanding that each JS file is loaded on the page? If so then the last file to be loaded is clobbering the previous document.onkeydown handler.
Each document can have only one document.onkeydown handler so you will have to do some clever event dispatching to be sure they are propagated to every piece of code that needs it. Common libraries such as jQuery and Google Closure will handle this for you. Here is an example in jQuery:
$(document).keydown(function(e) {
if (e.keyCode == 76) {
window.console.log("pressed l!");
}
});
$(document).keydown(function(e) {
if (e.keyCode == 71) {
window.console.log("pressed g!");
}
});
And a link to it working in action: http://jsfiddle.net/v7v4L/
Related
For example, I want to implement something like do action when you typed sequentially shift-s then s, in JavaScript. I'm inspired by Autohokey, hotkey configuration software/language for Windows, so I'm looking for a library or way to implement something that in JS.
So far I found a library called hotkeys, but I have no idea to implement a sequential keyboard hotkey and didn't find any issue or question about it also, so here I am. So, how can I implement that in JS using the library or other library? Thanks.
This can be done easy with keydown event listener, no library needed for this
sAgain = false
document.addEventListener('keydown', function(event) {
if (sAgain && event.key.toLowerCase() == 's')
alert("shift-s then s clicked")
else if (event.shiftKey && event.key.toLowerCase() == 's')
sAgain = true
else
sAgain = false //stop listen if other key is clicked after shift-s
});
<h1>Press shift s then s<h1>
I have a 'keydown' event on javascript for navigating table using arrow keys:
my code as follows:
document.onkeydown= function() { keyDown();};
The implementation code as follows:
function keyDown(e){
var evt=(e)?e:(window.event)?window.event:null;
var key = evt.keyCode || evt.which;
if(key==38 || key==40){
alert("working");
}
}
How can I make it works on all browsers? What I am doing wrong here?
You need to pass the event variable that the system passes in to your function or use the standardised addEventListener method:
// Passing the event
document.onkeydown = function(e) { keyDown(e); };
// Using event listeners
document.addEventListener('keydown', keyDown, false);
Then you should rely on the event passed - do not use window.event - if the event is not passed to your function you have bigger issues to worry about than finding the event.
function keyDown(e){
if(e.which == 38 || e.which == 40){
alert("working");
}
}
I would learn more about the addEventListener method as assigning functions to the documents own onEvent attributes is not advised. What if you want to change this later? What if you want to add some code some of the time? Event Listeners are great for that and they don't modify the default behaviour here. You can add and remove these on the fly, making it much more versatile. Have a read here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
I am writing a Greasemonkey script. I want to trigger a certain code to run when the user presses the "Q" key. I did a little bit of research, and most of the sources I saw suggested using window.onkeypress.
To test this method, I created a userscript set to run when the users presses Q. Here is my code:
window.onkeypress = function(event) {
if (event.keyCode == 81) {
alert("This is a test.")
}
}
However, upon pressing the Q key, nothing happened. I am wondering if anyone knows why this may be and what I can do to correct it.
In addition, if anyone knows of any other methods I can use to achieve the same effect, it would be greatly appreciated.
keypress events don’t receive a keyCode; try handling keydown instead.
window.onkeydown = function(event) {
if (event.keyCode === 81) {
alert("This is a test.");
}
};
I would like to use the following code to restrict input (to alphanumeric) into a text field:
$('input').bind('keypress', function (event) {
var regex = new RegExp("^[a-zA-Z0-9]+$");
var key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
if (!regex.test(key)) {
event.preventDefault();
return false;
}
});
The above code works great on a standard input field, but when I type into a field generated by Chosen, the function is not applied. The chosen plugin does generate a div containing <input type="text"> but $('input') doesn't seem to touch it. I'm guessing this is due to the timing of when the above code is applied..
Instead of .bind(), consider using .on() which will work for elements that are created dynamically.
Jack's answer works. But the important thing to understand is that the keypress event bubbles, so you can catch it anywhere up the node hierarchy, at a node that is not generated dynamically.
http://jsfiddle.net/KWv7Z/6/
$(document).bind('keypress', function (event) {
// Will fire for all elements, we only care for inputs
// Also allow navigation keypresses
if (event.target.tagName.toUpperCase() != "INPUT" ||
$.inArray(event.which, [8,9,13,16,17,18,19,20,27,33,34,35,36,37,38,39,40,45,46]) ) {
return;
}
var regex = new RegExp("^[a-zA-Z0-9]+$");
// jQuery already normalizes event.which
var key = String.fromCharCode(event.which);
if (!regex.test(key)) {
event.preventDefault();
return false;
}
});
This is also more memory friendly since it doesn't install a separate handler per input on the page.
How do I consume a key event in javascript, so that it doesn't propagate?
If you don't want the event to propagate and you're not using jQuery (or another library that wraps native browser events), you need to use the event's stopPropagation() method in most browsers and its cancelBubble property in IE. Don't bother with return false or preventDefault(): those only affect whether the native browser action happens for the event and have nothing to do with propagation.
For example:
document.onkeypress = function(evt) {
evt = evt || window.event;
if (typeof evt.stopPropagation != "undefined") {
evt.stopPropagation();
} else {
evt.cancelBubble = true;
}
};
Try preventDefault and/or stopPropagation.