I'm making a game using canvas, and javascript.
When the page is longer than the screen (comments, etc.) pressing the down arrow scrolls the page down, and makes the game impossible to play.
What can I do to prevent the window from scrolling when the player just wants to move down?
I guess with Java games, and such, this is not a problem, as long as the user clicks on the game.
I tried the solution from: How to disable page scrolling in FF with arrow keys ,but I couldn't get it to work.
Summary
Simply prevent the default browser action:
window.addEventListener("keydown", function(e) {
if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) {
e.preventDefault();
}
}, false);
If you need to support Internet Explorer or other older browsers, use e.keyCode instead of e.code, but keep in mind that keyCode is deprecated and you need to use actual codes instead of strings:
// Deprecated code!
window.addEventListener("keydown", function(e) {
// space and arrow keys
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
Original answer
I used the following function in my own game:
var keys = {};
window.addEventListener("keydown",
function(e){
keys[e.code] = true;
switch(e.code){
case "ArrowUp": case "ArrowDown": case "ArrowLeft": case "ArrowRight":
case "Space": e.preventDefault(); break;
default: break; // do not block other keys
}
},
false);
window.addEventListener('keyup',
function(e){
keys[e.code] = false;
},
false);
The magic happens in e.preventDefault();. This will block the default action of the event, in this case moving the viewpoint of the browser.
If you don't need the current button states you can simply drop keys and just discard the default action on the arrow keys:
var arrow_keys_handler = function(e) {
switch(e.code){
case "ArrowUp": case "ArrowDown": case "ArrowLeft": case "ArrowRight":
case "Space": e.preventDefault(); break;
default: break; // do not block other keys
}
};
window.addEventListener("keydown", arrow_keys_handler, false);
Note that this approach also enables you to remove the event handler later if you need to re-enable arrow key scrolling:
window.removeEventListener("keydown", arrow_keys_handler, false);
References
MDN: window.addEventListener
MDN: window.removeEventListener
MDN: KeyboardEvent.code interface
For maintainability, I would attach the "blocking" handler on the element itself (in your case, the canvas).
theCanvas.onkeydown = function (e) {
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
e.view.event.preventDefault();
}
}
Why not simply do window.event.preventDefault()? MDN states:
window.event is a proprietary Microsoft Internet Explorer property
which is only available while a DOM event handler is being called. Its
value is the Event object currently being handled.
Further readings:
https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/view
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
I've tried different ways of blocking scrolling when the arrow keys are pressed, both jQuery and native Javascript - they all work fine in Firefox, but don't work in recent versions of Chrome.
Even the explicit {passive: false} property for window.addEventListener, which is recommended as the only working solution, for example here.
In the end, after many tries, I found a way that works for me in both Firefox and Chrome:
window.addEventListener('keydown', (e) => {
if (e.target.localName != 'input') { // if you need to filter <input> elements
switch (e.keyCode) {
case 37: // left
case 39: // right
e.preventDefault();
break;
case 38: // up
case 40: // down
e.preventDefault();
break;
default:
break;
}
}
}, {
capture: true, // this disables arrow key scrolling in modern Chrome
passive: false // this is optional, my code works without it
});
Quote for EventTarget.addEventListener() from MDN
options Optional
An options object specifies characteristics about the event listener. The available options are:
capture
A Boolean indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.
once
...
passive
A Boolean that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. ...
This is the accepted answer rewritten for React.
import { useEffect } from "react";
const usePreventKeyboardScrolling = () => {
const onKeyDown = (e) => {
if (
["Space", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(
e.code
) > -1
) {
e.preventDefault();
}
};
useEffect(() => {
window.addEventListener("keydown", onKeyDown, false);
return () => window.removeEventListener("keydown", onKeyDown);
});
};
export { usePreventKeyboardScrolling };
Related
I am trying to disable arrow up and down function for a selection list field. I have searched and tried all the options but could not disable. When alerting with the keys it is working but when I try to disable it does not work. Is there any updates related with browsers
My Chrome Version: 89.0.4389.128 (Official Build) (64-bit)
// we are closing the arrow keys for selection
$(function()
{
$('.form-contact').on('keyup',function(e) {
if(e.keyCode === 38 || e.keyCode === 40) { //up or down
// alert(e.keyCode)
e.preventDefault();
return false;
}
});
});
Last code something like this. it does not prevent arrow up or down to the list but it prevents selection by enter from the list. So better than nothing. Still open my question.
$('.form-contact,.form-company,.form-address,.form-postcode,.form-phone,.form-email').on('keydown', (e) => {
if (e.target.localName != 'input') { // if you need to filter <input> elements
switch (e.keyCode) {
case 38: // up
case 40: // down
e.preventDefault();
break;
default:
break;
}
}
}, {
capture: true, // this disables arrow key scrolling in modern Chrome
passive: false // this is optional, my code works without it
});
Instead of keyup, use keydown event
$(function()
{
$('.form-contact').on('keydown',function(e) {
if(e.keyCode === 38 || e.keyCode === 40) { //up or down
// alert(e.keyCode)
e.preventDefault();
return false;
}
});
});
This might be helpful:
window.addEventListener("keydown", function(e) {
if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) {
e.preventDefault();
}
}, false);
Found it here Disable arrow key scrolling in users browser
I have a key press event listener on all direction keyboard keys which is setup when the page loads. I want to disable this event listener when the user reaches the finish line on my maze game. I have attempted to do this (see code below) but when the user reaches the finish line, the event listener remains active and the user can continue to move around the maze.
I would like to do this just using vanilla javascript. Any suggestions you have would be greatly appreciated.
Here is the event listener:
document.addEventListener("keydown", moveCharacter = (e) => {
let currentPos = naviCtrl.currentPosition(DOMstrings.boxes, DOMstrings);
document.querySelector(DOMstrings.timer).innerHTML = "";
const key_code = e.which || e.keyCode;
switch (key_code) {
case 37: //left arrow key
naviCtrl.moveLeft(currentPos, chosenCharacter);
playerCtrl.playerFinished();
break;
case 38: //Up arrow key
naviCtrl.moveUp(currentPos, chosenCharacter);
playerCtrl.playerFinished();
break;
case 39: //right arrow key
// naviCtrl.removeCharacter(DOMstrings);
naviCtrl.moveRight(currentPos, chosenCharacter);
playerCtrl.playerFinished();
break;
case 40: //down arrow key
naviCtrl.moveDown(currentPos, chosenCharacter);
playerCtrl.playerFinished();
break;
}
});
Here is what I have tried:
playerFinished: (currentPos) => {
if (document.querySelector(DOMstrings.characterImg).parentNode.id === 36 || document.querySelector(DOMstrings.characterImg).parentNode.id === "box-36") {
//1. stop player movement
document.removeEventListener("keydown", appController.moveCharacter);
}
},
Use document.removeEventListener("keydown", moveCharacter); since you defined moveCharacter and not navigationController.moveCharacter.
Here is my code. With this code if I press CTRL+S, the default behaviour is running along with Save() function and same with Open(). This means e.preventDefault() not working.
But this works perfectly on chrome or ie10.
Another thing, if I remove my function from the events, and keep only preventDefault(), the default behaviour is stopped as it should.
Whats wrong with my code?
document.onkeydown = function(e) {
var key = e.keyCode || e.which;
if (e.ctrlKey) {
switch (key) {
case 79: // Ctrl+O
e.preventDefault();
Open();
break;
case 83: // Ctrl+S
e.preventDefault();
Save();
break;
}
}
};
On Mac browsers, javascript does not receive keyup events for most keys (other modifier keys seem to be an exception) when the metakey is down. Use this jsfiddle to demonstrate (focus the result area and try something like cmd + x, the x will not receive a keyup event):
http://jsfiddle.net/mUEaV/
I've reproduced this in stable releases for Chrome, FF, Safari and Opera. The same thing does not seem to happen with the control key in Windows 7.
Is the OS hijacking the keyup event? This seems especially strange since commands that use the metakey such as save, find, cut, copy, etcetera all activate on keydown not on keyup, and can be hijacked by the javascript just fine.
It's simply not possible to get the onKeyUp events when meta is used, I learned today. Very unfortunate and difficult to work around. You'll have to emulate them some other way.
Edit: To clarify, this is only on Mac and occurs due to OS level handling of the event. It cannot be overridden. Sorry to be the bearer of bad news.
Although event.metaKey returns false, event.keyCode and event.key are still populated.
document.addEventListener('keyup', function(e) {
console.log(e.metaKey || e.key);
});
Click here then press the Command, Control, or Option keys.
Is the browser window retaining the focus when you press those keys? In windows you can get similar result when pressing windows+R or CTRL+ESC and similar key combinations that make browser to loose focus and that results in missed events.
While keyup events are indeed not available when the meta key is pressed, you can still get keydown events for all keys, as well as keyup events for the meta key itself.
This allows us to just simply keep track of the state of the meta key ourselves, like so:
let metaKeyDown = false;
window.addEventListener("keydown", event => {
if (event.key == 'Meta') { metaKeyDown = true; }
});
window.addEventListener("keyup", event => {
if (event.key == 'Meta') { metaKeyDown = false; }
});
By now additionally checking for the main key, plus cancelling the default behavior with Event.preventDefault() we can easily listen for key combinations (like here e.g. CMD+K) and prevent the browser from handling them:
let metaKeyDown = false;
window.addEventListener("keydown", event => {
if (event.key == 'Meta') { metaKeyDown = true; }
if (event.key == 'k' && metaKeyDown) {
event.preventDefault();
console.log('CMD+K pressed!');
}
});
window.addEventListener("keyup", event => {
if (event.key == 'Meta') { metaKeyDown = false; }
});
(Note the observation of the k key taking place already on keydown.)
Also, please be aware that when used incorrectly, this can break standard browser functionality (e.g. like CMD+C or CMD+R), and lead to poor user experience.
You can create an artificial keyup event by waiting for a certain period after the last keydown event. The only caveat is people will have different repeat rates on their os.
https://jsfiddle.net/u7t43coz/10/
const metaKeyCodes = ["MetaLeft", "MetaRight"];
const shiftKeyCodes = ["ShiftLeft", "ShiftRight"];
const ctrlKeyCodes = ["ControlLeft", "ControlRight"];
const altKeyCodes = ["AltLeft", "AltRight"];
const modifierKeyCodes = [
...metaKeyCodes,
...shiftKeyCodes,
...ctrlKeyCodes,
...altKeyCodes
];
// record which keys are down
const downKeys = new Set()
const artificialKeyUpTimes = {}
function onKeydown(e) {
downKeys.add(e.code);
// do other keydown stuff here
console.log("meta", e.metaKey, e.code, "down")
// check if metaKey is down
if (metaKeyCodes.some(k => downKeys.has(k))) {
downKeys.forEach(dk => {
// we want to exclude modifier keys has they dont repeat
if (!modifierKeyCodes.includes(dk)) {
// fire artificial keyup on timeout
if (!artificialKeyUpTimes[dk])
setTimeout(
() => fireArtificialKeyUp(dk, e),
500
);
artificialKeyUpTimes[dk] = Date.now();
}
});
}
}
function fireArtificialKeyUp(code, e) {
// if enough time has passed fire keyup
if (Date.now() - artificialKeyUpTimes[code] > 100) {
delete artificialKeyUpTimes[code];
//if key is still down, fire keyup
if (downKeys.has(code)) {
const eCode = isNaN(code) ? { code: code } : { keyCode: code };
document.dispatchEvent(
new KeyboardEvent("keyup", { ...e, ...eCode })
);
}
} else {
setTimeout(() => fireArtificialKeyUp(code, e), 100);
}
}
function onKeyup(e) {
downKeys.delete(e.code);
// do keyup stuff here
console.log("meta", e.metaKey, e.code, "up")
}
document.addEventListener("keydown", onKeydown)
document.addEventListener("keyup", onKeyup)
How do I go about binding a function to left and right arrow keys in Javascript and/or jQuery? I looked at the js-hotkey plugin for jQuery (wraps the built-in bind function to add an argument to recognize specific keys), but it doesn't seem to support arrow keys.
document.onkeydown = function(e) {
switch(e.which) {
case 37: // left
break;
case 38: // up
break;
case 39: // right
break;
case 40: // down
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action (scroll / move caret)
};
If you need to support IE8, start the function body as e = e || window.event; switch(e.which || e.keyCode) {.
(edit 2020)
Note that KeyboardEvent.which is now deprecated. See this example using KeyboardEvent.key for a more modern solution to detect arrow keys.
$(document).keydown(function(e){
if (e.which == 37) {
alert("left pressed");
return false;
}
});
Character codes:
37 - left
38 - up
39 - right
40 - down
You can use the keyCode of the arrow keys (37, 38, 39 and 40 for left, up, right and down):
$('.selector').keydown(function (e) {
var arrow = { left: 37, up: 38, right: 39, down: 40 };
switch (e.which) {
case arrow.left:
//..
break;
case arrow.up:
//..
break;
case arrow.right:
//..
break;
case arrow.down:
//..
break;
}
});
Check the above example here.
This is a bit late, but HotKeys has a very major bug which causes events to get executed multiple times if you attach more than one hotkey to an element. Just use plain jQuery.
$(element).keydown(function(ev) {
if(ev.which == $.ui.keyCode.DOWN) {
// your code
ev.preventDefault();
}
});
I've simply combined the best bits from the other answers:
$(document).keydown(function(e){
switch(e.which) {
case $.ui.keyCode.LEFT:
// your code here
break;
case $.ui.keyCode.UP:
// your code here
break;
case $.ui.keyCode.RIGHT:
// your code here
break;
case $.ui.keyCode.DOWN:
// your code here
break;
default: return; // allow other keys to be handled
}
// prevent default action (eg. page moving up/down)
// but consider accessibility (eg. user may want to use keys to choose a radio button)
e.preventDefault();
});
You can use KeyboardJS. I wrote the library for tasks just like this.
KeyboardJS.on('up', function() { console.log('up'); });
KeyboardJS.on('down', function() { console.log('down'); });
KeyboardJS.on('left', function() { console.log('right'); });
KeyboardJS.on('right', function() { console.log('left'); });
Checkout the library here => http://robertwhurst.github.com/KeyboardJS/
A terse solution using plain Javascript (thanks to Sygmoral for suggested improvements):
document.onkeydown = function(e) {
switch (e.keyCode) {
case 37:
alert('left');
break;
case 39:
alert('right');
break;
}
};
Also see https://stackoverflow.com/a/17929007/1397061.
Are you sure jQuery.HotKeys doesn't support the arrow keys? I've messed around with their demo before and observed left, right, up, and down working when I tested it in IE7, Firefox 3.5.2, and Google Chrome 2.0.172...
EDIT: It appears jquery.hotkeys has been relocated to Github: https://github.com/jeresig/jquery.hotkeys
Instead of using return false; as in the examples above, you can use e.preventDefault(); which does the same but is easier to understand and read.
You can use jQuery bind:
$(window).bind('keydown', function(e){
if (e.keyCode == 37) {
console.log('left');
} else if (e.keyCode == 38) {
console.log('up');
} else if (e.keyCode == 39) {
console.log('right');
} else if (e.keyCode == 40) {
console.log('down');
}
});
Example of pure js with going right or left
window.addEventListener('keydown', function (e) {
// go to the right
if (e.keyCode == 39) {
}
// go to the left
if (e.keyCode == 37) {
}
});
You can check wether an arrow key is pressed by:
$(document).keydown(function(e){
if (e.keyCode > 36 && e.keyCode < 41) {
alert( "arrowkey pressed" );
return false;
}
});
A robust Javascript library for capturing keyboard input and key combinations entered. It has no dependencies.
http://jaywcjlove.github.io/hotkeys/
hotkeys('right,left,up,down', function(e, handler){
switch(handler.key){
case "right":console.log('right');break
case "left":console.log('left');break
case "up":console.log('up');break
case "down":console.log('down');break
}
});
prevent arrow only available for any object else SELECT, well actually i haven't tes on another object LOL.
but it can stop arrow event on page and input type.
i already try to block arrow left and right to change the value of SELECT object using "e.preventDefault()" or "return false" on "kepress" "keydown" and "keyup" event but it still change the object value. but the event still tell you that arrow was pressed.
I came here looking for a simple way to let the user, when focused on an input, use the arrow keys to +1 or -1 a numeric input. I never found a good answer but made the following code that seems to work great - making this site-wide now.
$("input").bind('keydown', function (e) {
if(e.keyCode == 40 && $.isNumeric($(this).val()) ) {
$(this).val(parseFloat($(this).val())-1.0);
} else if(e.keyCode == 38 && $.isNumeric($(this).val()) ) {
$(this).val(parseFloat($(this).val())+1.0);
}
});
With coffee & Jquery
$(document).on 'keydown', (e) ->
switch e.which
when 37 then console.log('left key')
when 38 then console.log('up key')
when 39 then console.log('right key')
when 40 then console.log('down key')
e.preventDefault()