Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is_action_pressed sometimes skips key press #36396

Open
OlegDydy opened this issue Feb 20, 2020 · 11 comments
Open

is_action_pressed sometimes skips key press #36396

OlegDydy opened this issue Feb 20, 2020 · 11 comments

Comments

@OlegDydy
Copy link

OlegDydy commented Feb 20, 2020

Godot version:
3.2-stable

OS/device including version:
Windows 10 Home (Version: 1903, Build 18362.657)

Issue description:
Sometimes in-game keystroke events are skipped (this happens often when fps is low). This happens if you press them between frame updates. In my case, this happened with the “X” and arrow buttons. But I think there are many other cases when this can happen.

Steps to reproduce:
To reproduce this problem with a 99% guarantee, you will need to set the Frame Delay Msec to high value, for example, to 1000 (1 frame per second). Then need to press any arrow key and then X key (but before next render). In test you'll see x____

Minimal reproduction project:
KeyboardTest.zip (version 2)

If everything is OK, you'll see something like this x__<_ (pressing left then X) or this x^___ (pressing up then X)
If not, you'll only see x____ (when pressed any arrow key then X) or even _____.

Frame rate of demo already set to 1 frame per second

My thoughts on this issue:
I downloaded the source code of the engine and did a little research. I think the problem is in the WM_KEYPRESS event (most likely on the Windows side).
As I understand it, this is because the OS sets a flag to indicate that it is a key repeat, regardless of whether the program processed the keystroke or not. Thus, in the WM_KEYPRESS event, the 30th bit of lParam indicates that the arrow key was previously pressed (but the Godot did not know about it).
To fix this problem, it probably makes sense to change the 1183 line of os_windows.cpp to something like this:

bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_scancode());
k->set_echo((ke.uMsg == WM_KEYDOWN && last_is_pressed));
@nathanfranke
Copy link
Contributor

Cannot reproduce this on Windows 10 Pro 64 bit, (10.0, Build 18362)

Test project for those who need it:
Test.zip

var keys_pressed = 0

func _process(_delta):
	print(keys_pressed)
	if Input.is_action_just_pressed("ui_up"):
		keys_pressed += 1
	if Input.is_action_just_pressed("ui_down"):
		keys_pressed += 1
	if Input.is_action_just_pressed("ui_left"):
		keys_pressed += 1
	if Input.is_action_just_pressed("ui_right"):
		keys_pressed += 1
	if Input.is_action_just_pressed("x"):
		keys_pressed += 1

func _input(event):
	if event.is_action_pressed("ui_up"):
		keys_pressed += 1
	if event.is_action_pressed("ui_down"):
		keys_pressed += 1
	if event.is_action_pressed("ui_left"):
		keys_pressed += 1
	if event.is_action_pressed("ui_right"):
		keys_pressed += 1
	if event.is_action_pressed("x"):
		keys_pressed += 1

It prints out the total number of keys you pressed, so just keep pressing all 5 at once and make sure the number is divisible by 10 (2 checks of each type)

(Serious) Easy way to press all the arrow keys simultaneously. I had quite a bit of trouble with it.

@Calinou
Copy link
Member

Calinou commented Feb 21, 2020

@OlegDydy Does this occur if you disable input accumulation by calling Input.set_use_accumulated_input(false) in _ready()?

@OlegDydy
Copy link
Author

@Calinou No it does not. I don't use Input.set_use_accumulated_input(false) anywhere. The very first time I encountered this problem was when I figured out the standard Godot demo “2D Platformer Demo (kinematicbody)”

@OlegDydy
Copy link
Author

OlegDydy commented Feb 21, 2020

@nathanwfranke I think this version (KeyboardTest.zip) of the test demo will be much more informative (and yes, you do not need to press “X” and all the arrow keys, just “X” and any arrow key)

extends Node

var keys_pressed = ""

func _process(_delta):
	keys_pressed = ""
	keys_pressed += "x" if Input.is_action_pressed("x") else "_"
	keys_pressed += "^" if Input.is_action_pressed("ui_up") else "_"
	keys_pressed += "V" if Input.is_action_pressed("ui_down") else "_"
	keys_pressed += "<" if Input.is_action_pressed("ui_left") else "_"
	keys_pressed += ">" if Input.is_action_pressed("ui_right") else "_"
	print(keys_pressed)

If everything is ok, you'll see something like this x__<_ (pressing X and left) or this x^___ (pressing X and up)
If not, you'll only see x____
PS Using your method, I achieved a result when almost all the arrow keys were skipped (the demo printed x^___ despite the five keys pressed on the keyboard).

@dreamsComeTrue
Copy link
Contributor

dreamsComeTrue commented Feb 21, 2020

I've opened your project in current 'master' build. I've been pressing all buttons in random order - and as you see - all of them are being recorded properly.

demo

@OlegDydy
Copy link
Author

OlegDydy commented Feb 21, 2020

Need to press keys (eg X + Arrow up) at the same time (not hold X and then press arrows, this case have no problems).
PS Proof (Pressing X + arrow left)
proof
PSS In some sort of gaming software it might look like this:
macros

@dreamsComeTrue
Copy link
Contributor

Nope. Pressed X and arrow (and couple of them) at the exact same time. I've been also holding them for longer period to find if they start to flicker - but nothing funky happened - I've always had: x<^ in the output. Maybe it's something with your keybaord config (like key-strokes ratio) on Windows.
Does that error occur on other OS? Like, did you check it on Linux/macOS ?

@nathanfranke
Copy link
Contributor

Anyone who can reproduce this, make sure you have an anti-ghosting keyboard and no issues within keyboard testing apps.

@OlegDydy
Copy link
Author

@dreamsComeTrue I ran demo on Linux (on the same machine) and everything was fine. This only happens on Windows. Of course, I do not exclude the possibility of something wrong with my Windows installation, and not with Godot.

@OlegDydy
Copy link
Author

A small update. This error seems to depend on the frame rate. When I turn off VSync and make the frame rate unlimited, the problem disappears. And when I set the frame rate, for example, to 1 frame per second, it becomes more noticeable. For some reason key down event enters the program with is_echo() equals to true. In attached image the output from _unhandled_input callback.
изображение

@WebF0x
Copy link

WebF0x commented Jun 29, 2022

To add on @OlegDydy, here's a snippet to consistently reproduce the bug

extends Node

var should_be_zero_when_spacebar_released = 0

func _ready():
	assert(
		ProjectSettings["application/run/frame_delay_msec"] == 1000,
		"Set your frame rate to 1000 in Project > Project Settings > General > Application > Run > Frame Delay Msec")
	print("Tap spacebar between the frames/prints. If the counter increases, you reproduced the bug")
func _process(_delta):
	if Input.is_action_just_pressed("ui_accept"):
		should_be_zero_when_spacebar_released -= 1
	if Input.is_action_just_released("ui_accept"):
		should_be_zero_when_spacebar_released += 1
	print(should_be_zero_when_spacebar_released)

Output:

Tap spacebar between the frames/prints. If the counter increases, you reproduced the bug
0
0
1
2
3
4
5
5

When two actions are in the same frame, only the 2nd action of the frame is detected by the code.
It's possible to skip key presses as well as key releases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants