Alt keyup lost when doing alt-tab - javascript

I'm detecting alt with the following code. It works, but when I do alt-tab to switch to another program, I get a keydown of 18 (alt) and no keyup, and alt remains pressed. How can I solve this?
var altPressed = false;
$(document).keydown(function(evt) {
console.log("keydown", evt.which);
switch (evt.which) {
case 18:
altPressed = true;
break;
}
}).keyup(function(evt) {
console.log("keyup", evt.which);
switch (evt.which) {
case 18:
altPressed = false;
break;
}

Alt + Tab removes the focus on your main window, thus the keyup event will not fire.
Here's a probable solution you could use. I'm not sure if escape is being registered from which though, might have to use keyCode instead.
Example:
var altPressed = false;
$(document).keydown(function(evt) {
console.log("keydown", evt.which);
switch (evt.which) {
case 18:
altPressed = true;
break;
case 9: //tab key
case 27: //escape key
if(altPressed) {
altPressed = false;
}
break;
}
}).keyup(function(evt) {
console.log("keyup", evt.which);
switch (evt.which) {
case 18:
altPressed = false;
break;
});

As #Nathan points out correctly: Alt + Tab removes the focus on the main window, thus the keyup event will not fire.
Here is a solution that does not require jQuery and works for every focus loss:
Using the Blur event
Here is a VanillaJS example using your code, read more about the blur event in MDN docs
let altPressed = false;
function keyDownHandler(evt) {
if(evt.key === "Alt")
altPressed = true
}
function keyUpHandler(evt) {
if(evt.key === "Alt")
altPressed = false
}
document.addEventListener('keydown', keyDownHandler)
document.addEventListener('keyup', keyUpHandler)
window.addEventListener('blur', keyUpHandler)
Note: same as with #Nathans answer, this will not know whether the key is still down when moving back to the page (but with alt+tab it would not anyways).

Related

How to prevent keydown event listener from listening while inputting to a text field?

This is my additional code for reddit. It helps me browse it much quicker. The idea is based on 4chan's keyboard shortcuts. 'N' key for the next page and 'B' for the previous.
window.addEventListener("keydown", checkKeyPressed, false);
function checkKeyPressed(e){
switch(e.keyCode){
case 66:
window.location = document.querySelector('a[rel="nofollow prev"]').href;
break;
case 78:
window.location = document.querySelector('a[rel="nofollow next"]').href;
break;
default:
}
}
My problem is, the event also occurs when I type into a text field with the words that has 'n' or 'b' in it. How do I prevent it from happening when I focus to a text field?
As noted out by zerkms: i am not sure if you also want to detect text area's you should enhance the code further if you need support for such case...
window.addEventListener("keydown", checkKeyPressed, false);
function checkKeyPressed(e){
var elem = e.target;
var type = elem.getAttribute("type");
if(type!='text'){
switch(e.keyCode){
case 66:
//window.location = document.querySelector('a[rel="nofollow prev"]').href;
alert("case 66");
break;
case 78:
//window.location = document.querySelector('a[rel="nofollow next"]').href;
alert("case 78");
break;
default:
}
}
}

Binding arrow keys in jQuery except in input and textarea

I found this excellent question about binding the arrow keys with jQuery: Binding arrow keys in JS/jQuery with a great solution from Sygmoral:
$(document).keydown(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)
});
EXCEPT: This prevents the arrow keys from working the way they would usually work when the focus is in a text input field.
How would I modify this solution to allow the arrow keys to function normally when the current focus is in an input, text area, or another content editable area?
Put this in a condition:
$(document).keydown(function(e) {
if(!$(e.target).is(':input, [contenteditable]')){
switch(e.which){
// the cases as is
}
e.preventDefault(); // prevent the default action (scroll / move caret)
}
});
You can use event.target to get the target element of event, so you can check
var $target = $(e.target);
if($target.is("input") || $target.is("textarea")) {
//
}
Your editable element may have some common class
$('.input').keypress(function(event) {
var charCode = (evt.which) ? evt.which : event.keyCode
switch(charCode) {
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();
});

function to move character/camera when button pressed

I'm new here and also new with web coding. So i am trying to make a function to move my game character when a button is pressed. When button is pressed down a boolean value changes to "true" and the character moves. I was trying to do it somehow like this. Can someone light me up what is the best way to make this work? I need also to do this for all the rest buttons (a,s,d,arrows).
var wButton = false;
function newfunction()
document.querySelector('#keyButtonW').addEventListener('mousedown', function(event) {
keyButtonPressed("wButton", true);
});
document.querySelector('#keyButtonW').addEventListener('mouseup', function(event) {
keyButtonPressed("wButton", false);
});
document.querySelector('#keyButtonW').addEventListener('mouseleave', function(event) {
keyButtonPressed("wButton", false);
});
Assuming translate is a method to move your char, maybe you should make a big maskArray :
var keyboard = [];
function keyDown(e)
{
var key = event.keyCode || event.which;
keyboard[key] = true;
}
function keyUp(e)
{
var key = event.keyCode || event.which;
delete keyboard[key];
}
function keyAction() {
for (i in keyboard)
{
if (keyboard[i] == true)
{
switch(eval(i))
{
case 90: //Z
character.translateY(-1);
break;
case 83: //S
character.translateY(1);
break;
case 81: //Q
character.translateX(-1);
break;
case 68: //D
character.translateX(1);
break;
}
}
}
return false;
}
document.addEventListener("keydown", keyDown, false);
document.addEventListener("keyup", keyUp, false);
Simply put keyAction() inside your main loop / rendering loop.
The value of this is to not make lags happen when you hit a button, and help with multiple pressing management =)
EDIT
To get the key numbers, simply put a console.log(key) at the end of keyDown().

Disable keydown event defined by javascript in textarea and restore default behavior

I am using reveal.js by Hakim El Hattab to make presentation slides. I have added textarea to a slide. Within the textarea I want to prevent javascript functions from being called when certain keys are pressed, and restore the default behavior of typing. For example, as you can see from the lines of code below from reveal.js, when p is pressed, a function navigatePrev() is called. I want to prevent this function from being called and simply want p to be typed in the textarea when p is pressed. How can I do this using jquery? I tried adding the following script but that does not help.
<script>
$(document).keydown(function (e) {
if ($(e.target).is('textarea')) {
e.stopPropagation();
}
})
</script>
The functions defined in the reveal.js are still called. Using return false in place of e.stopPropagation() does not help either. I am also including the above jQuery lines at the very end on my page (after reveal.js is called).
Thank you.
Relevant lines from reveal.js
function onDocumentKeyDown(event) {
// FFT: Use document.querySelector( ':focus' ) === null
// instead of checking contentEditable?
// Disregard the event if the target is editable or a
// modifier is present
if (event.target.contentEditable != 'inherit' || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
var triggered = false;
switch (event.keyCode) {
// p, page up
case 80: case 33: navigatePrev(); triggered = true; break;
// n, page down
case 78: case 34: navigateNext(); triggered = true; break;
// h, left
case 72: case 37: navigateLeft(); triggered = true; break;
// l, right
case 76: case 39: navigateRight(); triggered = true; break;
// k, up
case 75: case 38: navigateUp(); triggered = true; break;
// j, down
case 74: case 40: navigateDown(); triggered = true; break;
// home
case 36: navigateTo(0); triggered = true; break;
// end
case 35: navigateTo(Number.MAX_VALUE); triggered = true; break;
// space
case 32: overviewIsActive() ? deactivateOverview() : navigateNext(); triggered = true; break;
// return
case 13: if (overviewIsActive()) { deactivateOverview(); triggered = true; } break;
}
}
The problem with your keydown event binding is that it binds to the document, which receives the event LAST (once it's too late to prevent the event from bubbling further up the DOM tree).
Instead, try binding the event directly to the textarea every time it is created:
// create text area & append to slide container
createTextAreaOnSlideContainer();
// bind an event handler to the element
$('textarea.slideTextArea').keydown( function(e) {
e.stopPropagation();
});
This will stop the event before it bubbles (propagates) up to the document that is listening for a key to be pressed
You can do this:
$(document).keydown(function(e){
if(!$('#textarea').is(':focus')){
yourfunction();
}
});
You just simply add an if statement inside and if the textarea is not focused then you call the function.

Prevent keypress event trigger when input is in focus

I am currently using a switch to trigger some code when a key is pressed. This isn't the exact code, but its basically what I am using (this is just for the sake of keeping it short and simple on here.)
$(document).keydown(function(e) {
switch(e.keyCode) {
case 39:
e.preventDefault();
alert("Arrow Key");
break;
case 37:
e.preventDefault();
alert("Arrow Key");
}
});
How can I prevent the events from firing when an input box is in focus?
I think you mean that you want to do e.preventDefault() only if the target element was not an input tag. You can do this like this:
$(document).keydown(function(e) {
if (e.target.nodeName.toLowerCase() !== 'input') {
switch(e.keyCode) {
case 39:
e.preventDefault();
alert("Arrow Key");
break;
case 37:
e.preventDefault();
alert("Arrow Key");
}
}
});
e.target is the element where the event originated. Alternatively, you can use jQuery's event delegation API:
$(document).delegate(':not(input)', 'keydown', function(e) {
switch(e.keyCode) {
case 39:
e.preventDefault();
alert("Arrow Key");
break;
case 37:
e.preventDefault();
alert("Arrow Key");
}
});
Edit Updated my answer to do "not an input" rather than "is an input" checks.
You can use document.activeElement which returns the currently focused element.
Brief doc from the MDN:
Returns the currently focused element, that is, the element that will get keystroke events if the user types any. This attribute is read only.
That is, in order to prevent keystroke events from firing when input is in focus, you can just ignore keystroke events handling when the focused element is an input
if (!$(document.activeElement).is("input"){ /* handle keystroke events here */ }
There may be a more elegant way but I would do something like this:
var inputHasFocus = false;
$("#some_input_id").focusin(function () {
inputHasFocus = true;
}).focusout(function () {
inputHasFocus = false;
});
and then use that in your case statement.

Categories