+2 votes

Environment: Windows 10 Pro 64bit, Chrome, Godot 3.0.2, GDScript

Goal is to capture the mouse on left clicking the Player node, then keep it captured as long as the left button is released.

Relevant code in the Player's script:

func _on_Player_input_event( viewport, event, shape_idx ):
    if event.is_action_pressed("player_select"):
        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event):
    if event.is_action_released("player_select"):
        Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

The player_select action is bound to the left mouse button in the project settings.

It works perfectly if run from the editor or exported as a Windows Desktop application (EXE).

The HTML5 exported version yields an error on left clicking the player:

**ERROR**: MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback
**ERROR**:    At: platform/javascript/os_javascript.cpp:596:set_mouse_mode() - Condition ' result == -2 ' is true.

What is the appropriate input callback to use in this case?

Thank you.

in Engine by (23 points)
edited by

This is the related code from os_javascript.cpp:596:set_mouse_mode()

EMSCRIPTEN_RESULT result = emscripten_request_pointerlock("canvas", false);
ERR_EXPLAIN("MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback");
ERR_FAIL_COND(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED);
ERR_FAIL_COND(result != EMSCRIPTEN_RESULT_SUCCESS);

The emscripten_request_pointerlock function is documented here:
https://kripken.github.io/emscripten-site/docs/api_reference/html5.h.html#registration-functions

Some functions, including emscripten_request_pointerlock() and emscripten_request_fullscreen(), are affected by web security.

While the functions can be called anywhere, the actual “requests” can only be raised inside the handler for a user-generated event (for example a key, mouse or touch press/release).

What is the right/best place in GDScript code to call Input.set_mouse_mode while satisfying the security requirements?

Found a really simple workaround:

var hovered = false

func _on_Player_mouse_entered():
    hovered = true

func _on_Player_mouse_exited():
    hovered = false

func _input(event):
    if event.is_action_pressed("player_select"):
        if hovered:
            select_player()
    elif event.is_action_released("player_select"):
        release_player()

Mouse capture works reliably now both on desktop and the Web.

Here is a tutorial on youtube in Spanish. You have to capture the mouse after loading the game, if you capture the mouse in the ready function it will not work.
Another important issue is that you call capture from the input (event) function

TUTORIAL YOUTUBE IN SPANISH CAPTURE MOUSE

1 Answer

+1 vote
Best answer

Guessing from the method signature, I assume _on_Player_input_event is the target of the input_event signal of a CollisionObject2D. Since this signal is emitted during physics processing (when checking collision between mouse position and collision shapes), it's a physics callback, and not an immediate input callback.

You can use the _input or _unhandled_input callback. In your case, this means you'll have to check for collision manually.
When working with GUIs, a Control node's _gui_input callback should also work.

by (1,090 points)
selected by

Thank you for your detailed answer and explanation.

It seems I need to do ray casting from the screen via the mouse position as described at the bottom of this tutorial: http://docs.godotengine.org/en/3.0/tutorials/physics/ray-casting.html

UPDATE: Please see the workaround in the comment on my original post.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.