Noninterrupting keyevents while preserving individual keystrokes - javascript

I am designing a keyboard interface through javascript, and I want to define keystroke combinations, like shift+rightkey or ctrl+tab. But after tinkering with javascript, as seen here, I've noticed that all keyevents are interrupting. In the provided example, if you go to hit the shiftkey while holding down the rightkey, the functionality of the rightkey is interrupted!
v = 1; /*v is the variable of velocity.*/
window.addEventListener("keydown", function(event)
{
if(event.keyCode == 39) /*39 is the keycode of rightarrowkey.*/
{
//moves an element by the velocity.
var keystroke = document.getElementById("keystroke");
keystroke.style.left = parseInt(keystroke.style.left.slice(0,-2))+v+"px";
}
if(event.keyCode == 16) /*16 is the keycode of shift.*/
{
//increases the velocity of the element by four.
document.getElementById("keystroke").style.borderColor = "red";
v = 4;
}
}, false); //but hitting the shiftkey while hitting the rightkey interrupts..!
I also experimented with recording all keystrokes through an object which is then iterated through at a designated interval for defined keystrokes, as seen here. But this system of handling the keyboard doesn't preserve the individual keystrokes; if I hit a key too fast, it may not be considered, or if I hold a key for too long, it may be overconsidered!

After giving it a bit of thought, I may have figured out a method to both preserve each keystroke while handling interrupting keyevents. My code is somewhat quirky, but it works well for managing the keystrokes from the users.
The solution to handling each keystroke without interruptions was through registering each keyevent within an object, as was previously suggested in my question. The code continually iterates through this object to handle any new keyevents.
But to ensure each keystroke is preserved and handled at least once, a keybinding must be registered for each keyevent. I expanded the scripting for the object to register both keystrokes as well as keybindings.
var kbdin =
{
stroked: new Object(),
upbinded: new Object(),
downbinded: new Object(),
downbindKeystroke: function(keycode, functionality) {this.downbinded[keycode] = functionality;},
upbindKeystroke: function(keycode, functionality) {this.upbinded[keycode] = functionality;},
isDownbinded: function(keycode) {return this.downbinded[keycode];},
isUpbinded: function(keycode) {return this.upbinded[keycode];},
isStroked: function(keycode) {return this.stroked[keycode];},
onDownstroke: function(event)
{
var keycode = event.keyCode;
if(!this.isStroked(keycode))
{
this.stroked[keycode] = 1;
if(this.isDownbinded(keycode))
{this.downbinded[keycode]();}
}
if(this.isDownbinded(keycode))
{event.preventDefault();}
},
onUpstroke: function(event)
{
var keycode = event.keyCode;
delete this.stroked[keycode];
if(this.isUpbinded(keycode))
{
this.upbinded[keycode]();
event.preventDefault();
}
},
handleKeystrokes: function()
{
for(var keycode in this.downbinded)
{
if(this.isStroked(keycode) > 5)
{this.downbinded[keycode]();}
}
for(var keycode in this.stroked)
{this.stroked[keycode]++;}
}
};
document.addEventListener("keyup", function(event) {kbdin.onUpstroke(event);}, false);
document.addEventListener("keydown", function(event) {kbdin.onDownstroke(event);}, false);
window.setInterval(function() {kbdin.handleKeystrokes();}, 50);
Now both the keystrokes and keybindings are coupled together, supporting each keyevent with the functionality to both signal a keystroke and execute a keybinding. It may be a bit quirky, but this code handles noninterrupting keyevents while still preserving individual keystrokes!

Related

Trapping keydown with basic JavaScript

I am fairly new to coding (Doing the foundation course on The Odin Project).
I am having some problems with the calculator project.
I want the calculator to be driven by both mouse & keyboard.
But when I press keys like "/", "." these are not trapped by Firefox or Chrome additionally Chrome is not trapping some more keys like "-" & "+".
window.addEventListener("click", mouseClick);
window.addEventListener("keydown", keyPress);
The keyPress function simply calls the element.click() so that mouseClick() is emulated.
It seems if I press the above keys - the keys are not trapped by the "click" event handler.
Any help will be highly appreciated.
My System Details:
Firefox 93.0 / Chrome 94.0.4606.81 on Fedora 34 x64.
The two functions are below, as requested:
A small addition: I have uBlock Origin/ Bitwarden installed in Firefox (no addons on chrome), but I guess they should not interfere in anyway?
window.addEventListener("click", mouseClick);
window.addEventListener("keydown", keyPress);
function keyPress(event){
let keyCode = event.keyCode;
if(keyCode === 13){
keyCode = 61;
}
let btnPressed = document.querySelector(`button[data-key="${keyCode}"]`);
if(!btnPressed){
return;
}
console.log(btnPressed);
btnPressed.click(); };
function mouseClick(event){
if(!(event.target.tagName === "BUTTON")){
return;
}
let currentButton = event.target.textContent;
if(event.target.classList.contains("num-key")){
if(tmpNumArray.some(item => (item === ".")) && currentButton === "."){
return;
}
tmpNumArray.push(currentButton);
currNum = tmpNumArray.join("");
refreshDisplay();
}else{
alert ("pressed operator");
} };

JavaScript keep track of which keys are down accurately

I have a web app that's running a 60FPS loop forever and I sometimes want to check whether a key is down now. So I made
var keydown = []
window.addEventListener("keydown", function(e){keydown[e.keyCode]=true})
window.addEventListener("keyup", function(e){keydown[e.keyCode]=false})
function loop() {
if(keydown[17]) console.log("Control is down.")
if(keydown[71]) console.log("F is down.")
}
setInterval(loop, 16)
The problem is that if the user presses control+F to search the page, then when they let go, the find window has focus and thus keyup does not fire. So my app thinks control and F are down forever. So I added this hack for the control key:
// Hack to fix control key being down forever.
window.addEventListener("mousemove", function(e){
if(keydown[17] && !e.ctrlKey) {
keydown[17] = false
}
})
What do I do about it thinking the F key is down forever? I have tried resetting all keys on visibilitychange but it doesn't fire when the user searches.
Here is the demo and source: http://touchbasicapp.com/testkeyup.html
This bug is on windows and mac, Chrome and Safari.
Clearing the array when the window loses focus (blur event) is probably your best option.
window.addEventListener("blur", function(e) {
keydown = [];
});
Unfortunately, I don't think there's any guarantee the browser will necessarily fire a blur event in the case of the search interface opening, but they probably should.
you need stop the key event for prevent the combinate:
var keydown = []
window.addEventListener("keydown", function (e) {
e.preventDefault();
keydown[e.keyCode] = true;
});
window.addEventListener("keyup", function (e) {
e.preventDefault();
keydown[e.keyCode] = false;
});
function loop() {
var comb = "";
if (keydown[17]) comb += "CTRL";
if (keydown[70]) {
if (keydown[17]) comb += "+";
comb += "F";
}
if ((keydown[17]) || (keydown[70])) console.log("I press " + comb);
}
setInterval(loop, 50);

Keypress is interfering with canv.onmousedown();

I'm trying to do two different actions when the canvas is clicked and when a key is pressed, but it seems like both can't be done at the same time. Is there a way to do this even if the functions are completely unrelated?
canv.onmousedown = function() {
console.log("Hello World");
};
And for keypress...
if(rightPressed && heroX < canvas.width) {
heroX += heroSpeed;
}
It can be done with single function. Listen for click event on canvas and check if it goes along with, for example shift being pressed.
function(e) {
if(!e.shiftKey) return; //it will do nothing unless shift key was pressed
}
You can do it for any button with e.keyCode property. For example e.keyCode === 32 would check if spacebar was pressed during the event. You can check any keyCode here.

How can I disable text selection using shift without disabling all text selection?

So I know this sounds like a duplicate, but it isn't (or if it is, the accepted answer on all the ones I can find doesn't work the way I need it to). The issue is this:
I'm writing in HTML5 using jQuery, I need to make a grid allow multi-select with control and shift. I have that logic working, but whenever you shift-click it selects the text in the grid. I want to prevent this selection, but here's the critical difference between this and the other questions I found: I want selection of text to work at all other times.
To restate: I want to disable text selection using shift WITHOUT disabling all text selection for the elements specified. Does anyone know how I can do that?
-- EDIT --
The following (in the constructor for the grid) solved this for me. As the answerer suggested, I declared a class for unselectability.
this.gridBody = $("#userGrid");
var handleKeydown = function(e)
{
e = e || window.event;
var keyPressed = e.keyCode || e.which;
if (keyPressed == keys.shift) {
e.data.gridBody.addClass("unselectable");
}
};
var handleKeyup = function(e)
{
e = e || window.event;
var keyPressed = e.keyCode || e.which;
if (keyPressed == keys.shift) {
e.data.gridBody.removeClass("unselectable");
}
};
$(document).on('keydown', this, handleKeydown);
$(document).on('keyup', this, handleKeyup);
That will bind on document an event where it disables text selection upon pressing DOWN shift
document.onkeydown = function(e) {
var keyPressed = e.keyCode;
if (keyPressed == 16) { //thats the keycode for shift
$('html').css({'-moz-user-select':'-moz-none',
'-moz-user-select':'none',
'-o-user-select':'none',
'-khtml-user-select':'none',
'-webkit-user-select':'none',
'-ms-user-select':'none',
'user-select':'none'
}); //or you could pass these css rules into a class and add that class to html instead
document.onkeyup = function() {
//here you remove css rules that disable text selection
}
}
}
Hopefully i have helped you.
Based on comments
document.onkeydown = function(e) {
var keyPressed = e.keyCode;
if (keyPressed == 16) { //thats the keycode for shift
$('html').addClass('unselectable'); //unselectable contains aforementioned css rules
document.onkeyup = function() {
$('html').removeClass('unselectable'); //and simply remove unselectable class making text selection availabe
}
}
}
Another solution you might consider: instead of preventing text selection by watching for shift keys and toggling selectability, you could just clear the text selection.
window.getSelection().removeAllRanges();
I find this more convenient because it can be run in your click handler to "cancel" the default behavior. Appears to work in IE 9+ and other modern browsers.

How to identify a long press on arrow keys in jQuery

I have two options to myself keypress and keydown. I am inclined to use keypress because it records an event, even if the key is repeated i.e. key is long pressed. But the problem is that keypress records special keys such as arrow keys only in Firefox. If I want to do it cross browser then I have to use keydown but then a long press will be recorded as a single event.
Any help is appreciated.
var pressed = null;
$(element).on('keydown', function(event) {
pressed = +new Date();
// do whatever else you need upon key down
});
$(element).on('keyup', function(event) {
var duration = +new Date() - pressed;
pressed = null;
// do whatever you need to do based on the duration of the press
});
I leave it as an exercise to you to work out support for multiple concurrent keys pressed.
You could use two events, like so:
var timer=false,
pressedTime = 1000; //one second
$('input').on({
keydown: function(e) {
var charCode = (e.which) ? e.which : event.keyCode, keyP;
if (charCode===37) keyP = 'left';
if (charCode===38) keyP = 'up';
if (charCode===39) keyP = 'right';
if (charCode===40) keyP = 'down';
if (!timer) timer = setTimeout(function() {
clearTimeout(timer);
timer=false;
alert(keyP+' arrow key held down for 1 second');
}, pressedTime);
},
keyup: function() {
clearTimeout(timer);
timer=false;
}
});​
FIDDLE
there's a plugin named jQuery Responsiveness which may help achieving this.

Categories