I'm working on a group formed with rects and transformers, now there's a need to move it in ways other than the mouse. Using containers I can move it using the arrow keys but with the group the Keydown function does not work, I already tried using group.on without success.
I would like that when clicking the arrows would start to work in the group moving it.
You can't listen to keyboard event on canvas nodes (such as Group or Shape) with Konva. But you can easily emulate it.
You can make Stage node focusable and listen to keyboard events on it. Then do required action in an event handler.
var container = stage.container();
// make it focusable
container.tabIndex = 1;
// focus it
// also stage will be in focus on its click
container.focus();
const DELTA = 4;
container.addEventListener('keydown', function (e) {
if (e.keyCode === 37) {
circle.x(circle.x() - DELTA);
} else if (e.keyCode === 38) {
circle.y(circle.y() - DELTA);
} else if (e.keyCode === 39) {
circle.x(circle.x() + DELTA);
} else if (e.keyCode === 40) {
circle.y(circle.y() + DELTA);
} else {
return;
}
e.preventDefault();
layer.batchDraw();
});
Demo: https://konvajs.org/docs/events/Keyboard_Events.htm
Related
Let's assume the simple pong game for two players with one keyboard.
The movement handler appears to be easy:
document.addEventListener('keydown', function (event) {
if (event.keyCode === 87) { //w
movePaddle(leftPaddle, 0);
} else if (event.keyCode === 83) { //s
movePaddle(leftPaddle, 1);
} else if (event.keyCode === 38) { //arrow_up
movePaddle(rightPaddle, 0);
} else if (event.keyCode === 40) { //arrow_down
movePaddle(rightPaddle, 1);
}
});
The second argument in movePaddle function just means the direction (up or down).
The problem: if W and Up Arrow are pressed together, then only one paddle moves. It depends on which key were pressed last.
How to handle keydown events correctly?
I need two paddles moving together according pressed keys. If W and Up Arrow, then both go up. If W and Down Arrow, then left goes up and right goes down. Of course, only one paddle should move if only one key are pressed.
https://gist.github.com/RepComm/52690eadaa9f4a3e7a7819b3267feca4
Use it like this: (In a loop of any kind, this one just uses anim frame)
Input.init();
var test = function () {
window.requestAnimationFrame(test);
if (Input.isKeyDown("w")) {
console.log("Forward March!");
}
}
window.requestAnimationFrame(test);
Try separating the keys by saying
document.addEventListener('keydown', function (event) {
if (event.keyCode === 87) { //w
movePaddle(leftPaddle, 0);
} else if (event.keyCode === 83) { //s
movePaddle(leftPaddle, 1);
}
// Separate them here
if (event.keyCode === 38) { //arrow_up
movePaddle(rightPaddle, 0);
} else if (event.keyCode === 40) { //arrow_down
movePaddle(rightPaddle, 1);
}
});
This will work because you're saying else if for every single one, that means that only one of them can be true at the same time.
What I'm saying is that when using else if, the else if is paired to the if, and much like just else, only one of the blocks can be true at the same time
Is there any way to identify right click event ("contextmenu") & scroll events while pointer lock API is enabled? I am trying to create a browser-based 3d game in which the player will be able to perform different activities by left clicking, right clicking, middle clicking and scrolling - while pointer is locked.
index.html
<body><button id="lock">Start game</button</body>
app.js
$("#lock").on("click", function(e) {
lockPointer(); // invokes the requestPointerLock API
e.stopPropagation();
});
// this works perfectly
$("body").on("click", function(e) {
// do stuff on left click
});
// this does not work
$("body").on("contextmenu", function(e) {
// do stuff on right click
});
For right click you can use mousedown or mouseup event, it works with requestPointerLock
$('body').on('mousedown', function(e) {
if (e.which === 1) {
// left button
} else if (e.which === 2) {
// middle button
} else if (e.which === 3) {
// right button
}
});
For scrolling you can use wheel event:
$('body').on('wheel', function(e) {
var dx = e.originalEvent.deltaX;
var dy = e.originalEvent.deltaY;
if (dy < 0) {
// scroll up
} else if (dy > 0) {
// scroll down
}
if (dx < 0) {
// scroll left (some mice support this)
} else if (dx > 0) {
// scroll right (some mice support this)
}
});
I'm using a script (impress.js) that bins some particular action to keyup and keydown events for left, right, up and down arrows.
In some particular moments (for example while typing in a textarea) I want back the default behaviour for the arrows.
I tried without success with
$("a#show-ta").click( function() {
document.addEventListener("keydown", function ( event ) {
if (event.keyCode >= 37 && event.keyCode <= 40) {
return;
}
});
document.addEventListener("keyup", function ( event ) {
if (event.keyCode >= 37 && event.keyCode <= 40) {
return;
}
});
});
where a#show-ta is the button that shows my textarea.
You want to prevent the keypress from bubbling up to the document where (I assume) Impress binds its handlers:
$("textarea").on('keyup keydown keypress', function(e) {
e.stopPropagation();
});
If you need the event in a specific zone, such as a texarea, you should stop the propagation of the event like this :
$('textarea').keydown( function(ev) {
ev.stopPropagation();
});
If the events are necessary for the whole page but you want to exclude while you are in a textarea, for example, you could raise a flag which you would validate in the event.
var keydownActivated = true;
$('textarea').keydown( function(ev) {
if (keydownActivated) {
ev.preventDefault();
// dostuff
}
});
This will more or less get you where you are going. Create a flag that tracks whether or not the textarea has focus, and check that flag in your current key press event handlers. I can't see all of your code, so this is just a simple example:
var textareaHasFocus = false;
var textarea = document.querySelector('#yourTextarea');
textarea.addEventListener('focus', function(event) {
textareaHasFocus = true;
}, false);
textarea.addEventListener('blur', function(event) {
textareaHasFocus = false;
}, false);
document.addEventListener("keydown", function ( event ) {
if (textareaHasFocus) return true;
// your current keyboard handler
});
document.addEventListener("keyup", function ( event ) {
if (textareaHasFocus) return true;
// your current keyboard handler
});
I am using the JQuery UI Dialog to create a pop-up. The pop-up has two buttons. The first button is automaticly selected by JQuery. I can change the selection between the buttons and the exit button with 'tab'.
I want to change the selection (only between the two buttons) also with the left and right arrow keys on the keyboard.
Where do I have to catch the arrow key down events and how can I change the focus of the buttons?
Thanks for your help!
I would do it something like that :)
$('body').on('keydown', '#terug', function(e) {
if (e.keyCode === 39) { //right arrow
$('#ok').focus();
}
});
$('body').on('keydown', '#ok', function(e) {
if (e.keyCode === 37) { //left arrow
$('#terug').focus();
}
});
Try it :) And if this won't work then go global without specifying selector in event definition:
$('body').on('keydown', function(e) {
if (e.keyCode === 39 && $('#terug').is(':focus')) { //right arrow
$('#ok').focus();
}
});
Hope this will help! :) If not give me a comment and i will try to fix this. :)
Thanks for your help! It worked. I added my solution to complete this question.
I bind the keydown event only on the ui-buttons:
$(document).on('keydown', '.ui-button', handleUIButtonKeyDown);
After that I handle the left and right arrow keys
function handleUIButtonKeyDown(event) {
if (event.keyCode == 37) {
//left arrow key pressed, select the previous button
makeButtonFocus($(this).prev(".ui-button"));
} else if (event.keyCode == 39) {
//right arrow key pressed, select the next button
makeButtonFocus($(this).next(".ui-button"));
}
}
function makeButtonFocus($button) {
$button.addClass("ui-state-focus");
$button.focus();
}
Here's a more generic answer
works on any number of buttons irregardless of DOM structure (btns need not be siblings)
$('body').on('keydown', function(e) {
if (e.keyCode === 37) { //left arrow
modalKeyboardNav("prev")
} else if (e.keyCode === 39) { //right arrow
modalKeyboardNav("next");
}
});
function modalKeyboardNav(dir) {
if (!$("body").hasClass("modal-open")) {
// no modal open
return;
}
var $curModal = $(".modal.show"),
$curFocus = $(document.activeElement),
$focusable = $curModal.find(".btn"),
curFocusIdx = $focusable.index($curFocus);
if (curFocusIdx < 0) {
// nothing currently focused
// "next" will focus first $focusable, "prev" will focus last $focusable
curFocusIdx = dir == "next" ? -1 : 0;
}
if (dir == "prev") {
// eq() accepts negative index
$focusable.eq(curFocusIdx - 1).focus();
} else {
if (curFocusIdx == $focusable.length - 1) {
// last btn is focused, wrap back to first
$focusable.eq(0).focus();
} else {
$focusable.eq(curFocusIdx + 1).focus();
}
}
}
I'm using the Camera jQuery slideshow on my site, but it lacks being able to control with keyboard which I need. In their google group someone posted the previous/next commands which work, however I still need the pause/resume keyboard button to work (in my case I'm using the spacebar). What would I need to enter to have .camera_play also controlled by the spacebar? Is that even possible?
Here is the code that pertains to the problem:
$(document.documentElement).keyup(function (event) {
// handle cursor keys
if (event.keyCode == 37) {//go left
$('.camera_prev').click();
} else if (event.keyCode == 39) { //go right
$('.camera_next').click();
} else if(event.keyCode == 32) { // spacebar to stop
$('.camera_stop').click();
After seeing how camera plugin works, you can use the :visible selector to click on the currently active action (which may be stop or resume), like this:
$(document.documentElement).keyup(function (event) {
// handle cursor keys
if (event.keyCode == 37) {//go left
$('.camera_prev').click();
} else if (event.keyCode == 39) { //go right
$('.camera_next').click();
} else if(event.keyCode == 32) { // spacebar to stop
$('.camera_stop , .camera_play').filter(':visible').click();
}
});
The documentation doesn't show this, but I dug into the code and it looks like when you click the stop button, it adds a class to the main wrapper called 'paused'. Here's how you can update the your code to handle both pausing and starting with the space bar.
$(document.documentElement).keyup(function (event) {
// handle cursor keys
if (event.keyCode == 37) {//go left
$('.camera_prev').click();
} else if (event.keyCode == 39) { //go right
$('.camera_next').click();
} else if(event.keyCode == 32) { // spacebar to stop
if($('.camera_wrap').hasClass('paused')){
$('.camera_play').click();
}
else{
$('.camera_stop').click();
}
}
}