Jump to content

ActionManager not firing OnKeyDownTrigger


Recommended Posts

I initialize an ActionManager and register an Action with it, using the OnKeyDownTrigger, like so:

scene.actionManager = new BABYLON.ActionManager(scene);
    new BABYLON.ExecuteCodeAction(
            trigger: BABYLON.ActionManager.OnKeyDownTrigger,
            parameter: "y"
        function () {
            console.log("y button pressed");

But when I press the "y" key on my keyboard nothing is logged to the console. I've tried with many others keys, in both Firefox and Chrome, after turning off all plugins. Typescript is throwing no errors.

Changing the trigger to BABYLON.ActionManager.OnEveryFrameTrigger works as expected, logging to console every frame. Changing it back to the "triggerOptions" object above makes it non-functioning again.

I also tried setting up an actionManager on a Mesh in the scene, and registering the Action with that, which didn't work either. (Although OnPickTrigger on the mesh works fine.)

Am I using the correct format for the triggerOptions object?

Should I not be instantiating the ActionManager directly on to the scene.actionManager property? (Although it works with OnEveryFrameTrigger.)

This code is nearly a copy-paste from the last code block under the Triggers section of "How to Use Actions". I can see the scene.actionManager object when I log it to console, with the action on it, it just isn't firing in response to pressing the y button.

I'm learning a lot about using Actions in Babylon, I just can't get keyboard inputs/actions to work. Thank you for any help, this is really getting to me!

Link to comment
Share on other sites

Hi SV!  Welcome to the forum.


Remember that you need to click on the canvas before the "y" listener goes active.

I cheated and used a canvas.focus() call in line 7.  Works for me... I see 'y' keypresses at the console.

Be sure to check-out https://www.babylonjs-playground.com/#15EY4F#2 as well.  It doesn't work perfectly, but it has an interesting keypress listener... might be worth playing-with.  

Link to comment
Share on other sites

Thanks for putting that Playground example together Wingnut. It's working for me, but my local Typescript implementation is still not working.

Using window.addEventListener for the Action works fine:

let yPress = new BABYLON.ExecuteCodeAction(
        trigger: BABYLON.ActionManager.OnKeyDownTrigger,
        parameter: "y"
    () => {
        console.log("y pressed");

window.addEventListener("keypress", (event) => {
    if (event.key === "y") {

That works. But doing this still does nothing:

scene.actionManager = new BABYLON.ActionManager(scene);

 Yet the actionManager calls ExecuteCodeActions for OnEveryFrameTrigger (the other Scene Trigger type), as expected.

I'm totally at a loss for why this is happening. It must be something about my development environment. I cleared my cache, turned off all browser plugins, tried two browsers, restarted my computer. Next, I might try hopping around on one foot and reciting Monty Python, just to see if it helps.

Using window event listeners will work, just a bit sad I can't get the ActionManager to work with keyboard events.

Thanks again for the help. If anyone has any ideas about where the problem could be, it would be much appreciated.


Link to comment
Share on other sites

For keyboard event to work you have to make sure that canvas.tabIndex = 1 (in order to have it receive the events)

Check with F12 object inspector in your browser to make sure that the canvas can receive keyboard events

Link to comment
Share on other sites

Alright, I figured out the problem. This has been one of the most intense multi-day debug sessions I've had in years.

After littering babylon.max.js with console.log statements, I narrowed it down to the fact that Engine._onCanvasFocus wasn't firing, while manually adding an event listener to the canvas focus event worked fine.

Then I noticed, that code was wrapped in a check for canvasOrContext.getContext. Ding ding ding. Winner winner, chicken dinner, as the kids say.

The problem was with this part of my code:

let canvas = <HTMLCanvasElement> document.getElementById("canvas2");
let gl = <WebGLRenderingContext> canvas.getContext("webgl");
let engine = new BABYLON.Engine(gl, true, {"preserveDrawingBuffer": true});

I had assumed that since the Engine's constructor took either a canvas or a context, that it would work fine with either.

But WebGLRenderingContext doesn't have a .getContext property!

I'm not sure if this is intended behavior, but the result is that the check for canvasOrContext.getContext silently fails (babylon.max.js line 11393, sorry, don't have the typescript line number).

Since that fails, much of the following option and Observable setup fails. The else part of "if (canvasOrContext.getContext)" is simply missing all of the setup code.

So, I think I discovered a bug in the engine? Or at least unintended behavior. I don't have the time or inclination to make the fixes and submit a pull request (this is my first week with Babylon afterall), but I hope someone can.

For now I've switched back to passing canvas to the engine constructor, and everything works as expected.

Side note: Having Scene.attachControl and Camera.attachControl have the same method name, while doing very different things, was a source of confusion for me.

Edit: This may be intended behavior, just undocumented. It's very unintuitive that Observables aren't properly setup when passing a WeblGLRenderingContext to Engine, while HTMLCanvasElement works fine. The fact that you can't addEventListener on WebGL contexts is probably the source of that difference.

A reasonable compromise would just be mentioning in the documentation that initializing Engine with a WebGlRenderingContext prevents (some?) Observables from being setup.

Edit2: Apparently you can get the canvas from the context, so event listeners could still be setup, so long as the canvas is not null.

Link to comment
Share on other sites

Well this is expected actually :) if you provide a context, this is a signal for babylon.js that there is already something working on the webgl context and we are a plugin (this is how the integration in PowerPoint works for instance)

So in this case, the footprint is minimal as we do not own the canvas (so no event hooking etc..). i will mention that in the code comments


Thanks a lot for your feedback!

Link to comment
Share on other sites

Good to know, thanks. Hopefully if/when someone runs into the same situation, something is there to say "Observables are not registered when using a WebGLRenderingContext." Either in documentation, code comments, or console warnings. Anything but failing silently with no indication as to why the Observables aren't being set up.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...