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

[core] IsKeyPressed / GetKeyPressed #535

Closed
egonelbre opened this issue May 8, 2018 · 8 comments
Closed

[core] IsKeyPressed / GetKeyPressed #535

egonelbre opened this issue May 8, 2018 · 8 comments

Comments

@egonelbre
Copy link

egonelbre commented May 8, 2018

Copied information from gen2brain/raylib-go#36 (comment), because the original issue was closed and probably warrants a clear decision.

The example code in raylib uses IsKeyPressed https://github.com/raysan5/raylib/blob/master/examples/text/text_input_box.c#L55.

However looking at raylib API it looks like something that could be improved. The GetKeyPressed has a problem that it might lose characters with quick typing and you might end up with a buggy text-box.

For text input you want to separate "characters" and other keys, because you have case-sensitivity and utf-8... I suspect here the GetKeyPressed is meant as GetLastCharacterPressed. You never want to mix these two, otherwise there will be pain.

For raylib the right approach would be probably to have a buffer that gets cleared each frame so that you can consume all the keys in order that happened during the frame. e.g.

while(rune r = GetPressedCharacter()) { ... }

However this has the problem that it wouldn't be able to distinguish between characters and modifiers. There's a possibility to using something like:

while(input ev = GetInputEvent()){
	switch(ev.type){
	case INPUT_KEY: ...; break;
	case INPUT_CHARACTER: ...; break;
	}
}
// or 
while(input ev = GetInputEvent()){
	if(ev.key) { ... }
	if(ev.character) { ... }
}

Other APIs:

  1. GLFW: http://www.glfw.org/docs/latest/input_guide.html#input_keyboard
  2. SDL2: https://wiki.libsdl.org/SDL_Event
@irskep
Copy link

irskep commented Feb 3, 2019

If you're looking for a good design to work from, BearLibTerminal has an event model worth stealing. http://foo.wyrd.name/en:bearlibterminal

Events are always in a queue. You can "read" an event to get its value, which also consumes it, or you can "peek" without consuming it. There are convenience functions to test whether keys are down (I think). There is also a completely separate API for handling "string" input, for things like multi-character UTF-8 input.

Event handling is very much worth getting right.

@raysan5
Copy link
Owner

raysan5 commented Feb 3, 2019

Hi @irskep! Thanks for the reference!

Actually, redesigning that functionality is planned but not enough resources to make it soon.

@Berni8k
Copy link
Contributor

Berni8k commented Apr 9, 2019

For the Raspberry Pi platform this was fixed in #785 by introducing a FIFO buffer for keydown events.

It was made compatible with the existing API by pushing any extra key presses within this frame onto the next frames. Perhaps this functionality should be ported to other platforms too?

@raysan5
Copy link
Owner

raysan5 commented Apr 10, 2019

@Berni8k On RPI keyboard events reading runs in a second thread, so, it makes sense the FIFO buffer but on other platforms, raylib is tied to GLFW functionality. glfwSetCharCallback() is used to get unicode character pressed that it is registered in lastKeyPressed, returned by GetKeyPressed(). That check happens per frame, on GLFW events polling.

Using this mechanism it's possible to store all pressed unicode characters on a certain frame into a MAX_KEYS_REGISTERED array, just in case multiple keys are pressed at once (similar to what IsKeyPressed() uses) but I don't think it gives much added-value in comparison to current implementation. Is there any specific situation when we need to retrieve all unicode codepoints generated in a single frame instead of just checking for keys being pressed?

The GetKeyPressed has a problem that it might lose characters with quick typing and you might end up with a buggy text-box.

It would only happen if typing more than 60 characters per second or multiple characters are typed at once. Used current implementation with raygui GuiTextBox() and never had that problem.

However this has the problem that it wouldn't be able to distinguish between characters and modifiers.

GLFW also provides glfwSetCharModsCallback() to receive unicode points plus modifiers if required but unicode codepoints (text characters) provided by glfwSetCharCallback() should be enough. To check modifier pressed keys we already have them available in IsKeyPressed() array.

@egonelbre
Copy link
Author

It would only happen if typing more than 60 characters per second or multiple characters are typed at once.

This isn't really about more than 60 characters per second, but more about 2 characters in 16ms. People type in bursts not at a consistent speed. If you have some sort of speech-to-text system, then it can quite easily happen that you get 8 characters under 16ms, although in game context it probably is quite rare.

@Berni8k
Copy link
Contributor

Berni8k commented Apr 10, 2019

If the framerate dips below 60fps this window becomes larger tho. Dips to 30fps are common and that widens the window to 33ms. Likely possible for a fast typist to hit two keys within 33ms if they are pressed by separate hands. Even more likely that this happens if the game is 2 player local multiplayer. In such a case players hitting keys at a average rate of 1 per second would on average get a missed key once per minute (If the game runs at 60fps)

Its not a big deal if you ask me. But since it only takes 10 lines of C code to solve using a FIFO to move missed key presses onto the next frame, its probably worth adding it in. glfwSetCharCallback() puts keypresses into the FIFO while the on every start of the frame the FIFO shovels the last keypress into lastKeyPressed. This keeps the existing API and only misses a key if the user constantly maintains a >60 character per second typing speed to fill the FIFO up (Not possible for even the fastest typist in the world).

I can make a pull request with such a fix if wanted.

@raysan5
Copy link
Owner

raysan5 commented Apr 13, 2019

@egonelbre @Berni8k I agree it's not a big deal to improve it so we can add that fix.

Just one concern, would it be possible to implement it without any additional struct, only plain data types? I mean just the array and two counters.

@raysan5
Copy link
Owner

raysan5 commented May 1, 2019

@Berni8k did you check this improvement?

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

No branches or pull requests

4 participants