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

[Feature] Add IsKeyRepeated and key safety checks #3248

Closed
wants to merge 0 commits into from

Conversation

nickyMcDonald
Copy link
Contributor

Hi, In order to make it possible to pick up repeated key events I have added the bool GetKeyRepeat(int key) function.
A good example of where this would be essential would be in the 'input box' example.
Replace:

if (IsKeyPressed(KEY_BACKSPACE))
{
    letterCount--;
    if (letterCount < 0) letterCount = 0;
    name[letterCount] = '\0';
}

With:

for (bool pressed = IsKeyPressed(KEY_BACKSPACE); pressed || GetKeyRepeat(KEY_BACKSPACE); pressed = false)
{
    letterCount--;
    if (letterCount < 0) letterCount = 0;
    name[letterCount] = '\0';
}

If you have any questions about renaming, changing, removing or anything else please let me know.
I do not expect the current changes in the pr to be set in stone.

@raysan5
Copy link
Owner

raysan5 commented Aug 18, 2023

@n77y I understand this functionality returns true for one frame every certain time (i.e. every 10 frames, depending on the framerate), right?

I'm seeing several PRs requiring key-repeat detection functionality. Personally, I never needed it, it just managed it myself using exposed functions. First of all, that functionality does not seem to be available in all supported platforms, only PLATFORM_DESKTOP (correct me if I'm wrong), second, I got many programs depending on keys input and managing key-repeat myself, not sure how those changes could affect my code (or other users codebases in similar situation).

Why is that feature so important? What are the problems of just managing the key-repeats with already provided functionality?

@nickyMcDonald
Copy link
Contributor Author

You would know more than me about whether this would work only on a desktop or not. I could not find any GLFW docs that specified any platform support for GLFW_REPEAT. If that is an automatic game breaker then this pr can be closed, however wouldn’t GetCharPressed only work with desktop as well?

I understand that the GLFW_REPEAT and GLFW CharCallback are both capped at the framerate, however when the framerate is above the char-repeat rate they behave according to the system's settings and not any hardcoded values.

A great example would be if I managed the key-repeat to match my system's. Then my app is used by another user, and they have a different repeat-rate on their system. This would result in inconsistent repeat rates with various keys.

The best workaround I can see with the current state of raylib and its bindings would be to use GetKeyPressed instead of GetCharPressed so I can write my own repeat functionality that's consistent with all the keys and implement a repeat speed setting.

The changes are not designed to change the functionality of any current code bases, that could obviously break their functionality and that would not be ideal. Rather this is intended as a feature meant for newer codebases and older if chosen to add it.

@nickyMcDonald
Copy link
Contributor Author

If GLFW_REPEAT is confermed to be desktop only then this pr can be closed and @actondev's pr #3245 would work in this case.

@raysan5
Copy link
Owner

raysan5 commented Aug 19, 2023

A great example would be if I managed the key-repeat to match my system's. Then my app is used by another user, and they have a different repeat-rate on their system. This would result in inconsistent repeat rates with various keys.

Yes, that's it, depending on the OS and maybe keyboard driver the key-repeat events could not be consistent between systems.

The best workaround I can see with the current state of raylib and its bindings would be to use GetKeyPressed instead of GetCharPressed so I can write my own repeat functionality that's consistent with all the keys and implement a repeat speed setting.

That's similar to what I do on some of my tools, I just manage the key-repeats myself checking if IsKeyDown() and measuring the timming to allow key-repeat behaviour. Timming is usually consistent between platform and functionality does not rely on the OS or driver. But in that case the user experience could not be the best for the user and the implementation cost is a bit higher.

If GLFW_REPEAT is confermed to be desktop only then this pr can be closed and @actondev's pr #3245 would work in this case.

I'm looking to the several related issues/PRs to see the best option for raylib.

@nickyMcDonald nickyMcDonald changed the title [Feature] Add GetKeyRepeat [Feature] Add IsKeyRepeated (targeting as many platforms as possible) Aug 19, 2023
@nickyMcDonald
Copy link
Contributor Author

@raysan5, I have made a few changes. I renamed it to IsKeyRepeated because its only one repeat per frame only.

if (IsKeyPressed(KEY_BACKSPACE) || IsKeyRepeated(KEY_BACKSPACE))
{
    letterCount--;
    if (letterCount < 0) letterCount = 0;
    name[letterCount] = '\0';
}

Internally there are a few changes as well.
If you prefer my previous commit let me know so I can revert it.

src/rcore.c Outdated

CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode;
CORE.Input.Keyboard.keyPressedQueueCount++;
}
else CORE.Input.Keyboard.currentKeyState[keycode] = 0; // Key up
else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) KEY_STATE(keycode) = KEY_STATE_RELEASED;
else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE) KEY_STATE(keycode) = KEY_STATE_REPEATED;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raysan5, also it would appear that andriod supports repeated keys perhaps.

@ghost
Copy link

ghost commented Aug 19, 2023

I'm sorry, but is this really necessary? It appears to be a big change from the standard logic of directly accessing CORE.* which is used everywhere (and is really handy).

IMHO, if some keypress repeated function is to be added, I'd rather something like #3245 which is more minimal and isolated.

src/rcore.c Outdated
char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
char keyState[MAX_KEYBOARD_KEYS]; // Registers frame key state
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ubkp, correct me if im wrong. The issue is this change? I was unware CORE was used so oftin if this is the case. I can make some changes to the pr if you can be more specific with what the issue is.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n77y That too, but I was mostly looking at FLAGS_CHECK(KEY_STATE(key)... and KEY_STATE(.... Right now I can tap into anything CORE.* and extend it directly/easily without breaking anything and keeping fully upstream compatibility. Your PR proposes a different logic, it changes too much.

IMHO, keypress repeated should be handled by the user (it's not a one size fits all), but if that's to be added, I'd much rather an approach that keeps it mostly isolated/independent to not break what is already working really well. That's why I mentioned #3245.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ubkp, I have taken your requests and staged them.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n77y That's looking so much better. But why are you implementing a KEY_SAFE(...?

Personally, I don't think that making IsKeyPressed() require IsKeyDown() and IsKeyReleased() require IsKeyUp() would be a good idea, makes them dependent. IMHO, the current implementation is very resilient due to being independent of each other. Does those functions really need to change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ubkp, I believe KEY_SAFE(key) to be necessary due to the exposed nature of the IsKey...'s. It only seems mandatory to ensure that we aren’t reading memory we aren’t supposed to and rather simply return false when the user inputs a invalid key.

I agree, removing dependencies on the IsKey...'s is sensible. I removed them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KEY_SAFE(key) macro removed. Replaced with normal safety checks

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n77y Regarding the key safe check, the first sentence of this comment #3246 (comment) comes to mind. So I assumed it was up to the user to validate that. I'm not against it tho, I think that's good.

Just tested your PR on PLATFORM_DESKTOP (Linux Mint 21.1 64-bit) and PLATFORM_WEB (Chromium 115.0.5790.170 64-bit and Firefox 115.1.0esr 64-bit, both on Linux), and it's working great. Very good job.


Tested with:

#include "raylib.h"

int main(void) {
    InitWindow(800, 450, "test");
    SetTargetFPS(60);
    while (!WindowShouldClose()) {

        if (IsKeyRepeated(KEY_ONE)) TraceLog(LOG_INFO, "1 repeated");

        BeginDrawing();
        ClearBackground(RAYWHITE);
        EndDrawing();
    }
    CloseWindow();
    return 0;
}

@nickyMcDonald nickyMcDonald changed the title [Feature] Add IsKeyRepeated (targeting as many platforms as possible) [Feature] Add IsKeyRepeated and key safety check Aug 20, 2023
@nickyMcDonald nickyMcDonald changed the title [Feature] Add IsKeyRepeated and key safety check [Feature] Add IsKeyRepeated and key safety checks Aug 20, 2023
@ghost
Copy link

ghost commented Aug 20, 2023

@n77y Sorry to bump this again. But today I compared this PR with @actondev PR (#3245) and (after all the changes) this PR ended up being almost the same as @actondev PR. So, since he presented that solution first, I think his PR should be the accepted one.

This PR, however, adds key safe checks, Raspberry Pi and Android support. So, these improvements could be added after @actondev PR.

Either way, I'd suggesting waiting to see what @raysan5 decides to do about keypress repeated before moving further.

@raysan5
Copy link
Owner

raysan5 commented Aug 20, 2023

@ubkp I agre that @actondev solution could be merged first and any further improvement could be added as a separate PR.

Despite it isolated nature, not affecting current functionality (something that I love), this is a big change and I prefer to keep PRs as small and self-contained as possible.

src/rcore.c Outdated
// Check if a key has been repeated
bool IsKeyRepeated(int key)
{
if ((key < 0) || (key >= sizeof(CORE.Input.Keyboard.currentKeyState))) return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not important, but some comments:
Should be sizeof(repeatKeyState). But then, use another array every time? Checking with MAX_KEYBOARD_KEYS instead could make things consistent.

That said, I think these should be asserts instead. If you call this some invalid value this is a silent failure.

bool static IsValidKey(int key) {
return key >= 0 && key < MAX_KEYBOARD_KEYS);
}
// and using it
assert(isValidKey(key));

I have no objections with merging this one instead, since more platforms seem to work as well!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking with MAX_KEYBOARD_KEYS instead could make things consistent.

Agree.

I think these should be asserts instead. If you call this some invalid value this is a silent failure.

I'm afraid raylib does not use assert() anywhere. It can just TraceLog(LOG_WARNING, ...) if really required.

@raysan5
Copy link
Owner

raysan5 commented Aug 20, 2023

@actondev Just merged your PR.

@n77y Required improvements from this PR could be added to already added PR.

@actondev
Copy link
Contributor

@raysan5 I fucked up apparently in the last moment force push, apologies!
@n77y could you fix this bit? b3f82a1#diff-39fea0e3daa23741e81daf967717f35c7842426aab26a0bc3f525d6a2f03e339R3763-R3764 to return false; 🤦

@nickyMcDonald
Copy link
Contributor Author

@actondev, @raysan5, @ubkp, #3256

raysan5 added a commit that referenced this pull request Sep 17, 2023
* Prettified a comment

* fixed broken indentation caused by another commit.
the commit renamed a bool to int and broke indentation: 233cf39

* Changed 0.001 and 0.00001 to EPSILON
This commit is untested.
I don't know what consequences this has.
Since the commits that added these numbers were before epsilon was added,
I have assumed that epsilon could replace them.

* Prettied up indentation in a few places

* removed spacing around *, standardizing it.

* I may have gotten overboard with indentation

* removed a few useless parenthesis

* Added fortran-raylib

* Fix examples/others/rlgl_standalone.c compilation issue (#3242)

* Update BINDINGS.md

* Ignore unused return value of GetCodepointNext in GetCodepointCount (#3241)

* Ignore unused return value of GetCodepointNext in GetCodepointCount

Removes the last warning from non-external libraries when compiling with
the default build configuration on x64 Linux.

* Remove unnecessary void cast in GetCodepointCount

* Fix #3246

* Revert "Fix #3246"

This reverts commit e4dcbd5.

* Fix text_unicode.c example crashing (#3250)

* Fix text_unicode.c example crashing

* Adjust the text_unicode.c example crashing fix

* tweaks

* add build.zig options for individual modules (#3254)

* Add `IsKeyPressedRepeat` (desktop only) (#3245)

Since the key pressed are handle by comparing current vs previous
state (ie frame), a special way is needed to handle key repeats.

* Reviewed `IsKeyPressedRepeat()` #3248

* Update rcore.c (#3255)

* Match CMakeOptions.txt options default values (#3258)

* Fix SetClipboardText for web (#3257)

* [Image] Validate that ImageDrawRectangleRec is drawing entirely inside the image (#3264)

* Add a function to clone a sound and share data with another sound.

* rename items based on feedback

* PR Feedback, use custom unload for sound alias, not variant of normal sound unloading

* sound_multi example

* Validate that image rect drawing is inside the image so we don't overflow a buffer

* remove files that should not have been added.

* remove changes that should not have been

* revert

* adsfasdfsdfsdf

* Add Vector3 Projecting and Rejection to Raymath (#3263)

* Update raymath.h

* formatting

* [Feature] IsKey... safety checks and more (#3256)

* [Feature] Add GetKeyRepeat

* Update rcore.c

* Simpler design, only one repeat per frame

* Update config.h

* Update rcore.c

* Add KEYBOARD_KEYS_MASK

* Update config.h

* reversions

* Update rcore.c

* Update rcore.c

* change docs

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update raylib.h

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Fix bug where default shaders was not linking. (#3261)

* Formating review

* Add missing cmake options (#3267)

* Fix CMake extraneous -lglfw (#3266)

Closes #3265.

The problem: LIBS_PRIVATE is a list of library names (used by pkg-config), but the shared library of the same name doesn't always exist.

* Fix example/models/models_loading_gltf.c controls (#3268)

* Fix example/models/models_loading_m3d.c controls (#3269)

* Remove e from secondes (#3270)

* Fix example/audio/audio_module_player.c help instructions and small bug (#3272)

* Fix example/audio/audio_module_player.c help instructions and small bug

* Update example/audio/audio_module_player.png screenshot

* Use type name instead of valid specifier

long long --> long long int

* REVIEWED: `GetFileLength()`, added comment #3262

* Update examples/models/models_loading_gltf.png;m3d.png screenshots (#3273)

* Remove a duplicated screenshot and add missing one (#3275)

* Add examples/shaders/shaders_lightmap.c to Makefiles (#3276)

* Fix examples/others/easings_testbed.c help instructions and small tweak (#3277)

* Fix examples/shaders/shaders_texture_outline.c help instructions (#3278)

* Fix examples/shapes/shapes_collision_area.c help instructions (#3279)

* RENAMED: LoadFont*() parameter names for consistency and coherence

* Fix uninitialized thread-locals in stbi #3282 (#3283)

* REVIEWED: Added `SetTextLineSpacing()` to multiline examples

* REVIEWED: Data size type consistency between functions #3168

* Some tweaks

* Use internal default allocators, instead of user-exposed ones

* Added rudimentary SVG support. (#2738)

* Added rudimentary SVG support. Added 2 functions ImageLoadSvg and ImageLoadSvgWithSize.

* Added an example on how to use ImageLoadSvgWithSize and adjusted Makefiles accordingly.

* Added actual correct example file.

* Reviewed the code to keep the raylib coding conventions in mind.
Moved the LoadImageSvg() code into LoadImage() guarded by SUPPORT_FILEFORMAT_SVG.
Renamed LoadImageSvgWithSize() to LoadImageSvg().
Added a LoadImageSvgFromString() function to parse the loaded SVG into an actual image. This does the bulk of the work.

* Fixed typo.

---------

Co-authored-by: Ray <[email protected]>

* REVIEWED: `LoadImageSvg()`

* REVIEWED: `LoadImageSvg()`

* Add SUPPORT_FILEFORMAT_SVG to cmake (#3284)

* Fix examples/textures/textures_fog_of_war.c help instructions (#3285)

* Fix examples/textures/textures_image_rotate.c help instructions (#3286)

* Update rtextures.c

* Fix #3247

* Update config.h

* Fix #3293

* Disable UBSAN in zig builds. (#3292)

Zig debug builds automatically enable ubsan.
As the fix for #1891 had to be reverted, debug builds using zig will crash like so:

```
Illegal instruction at address 0x3237d2
raylib/src/rlgl.h:3690:91: 0x3237d2 in rlDrawVertexArrayElements (/home/rcorre/src/raylib-zig-template/raylib/src/rcore.c)
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset);
```

This disables UBSAN when using zig to build raylib.

* Update README.md (#3290)

specially -> especially

* Update cmake SUPPORT_FILEFORMAT_SVG default value (#3291)

* Mouse offset and scaling must be considered also on web!

* Update rcore.c

* Update Makefile : clean raygui.c & physac.c (#3296)

* Remove PLATFORM_RPI (#3232)

* Remove PLATFORM_RPI

* remove build artifacts

---------

Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: Ray <[email protected]>

* Review to avoid UBSAN complaining #1891

* added raylib-raku to bindings (#3299)

* examples: core: adds 2D camera two player split screen (#3298)

* Reviewed examples for consistency

* Update rtext.c

* Some code restructuring for input functions, consistency review

* Remove unneeded #if (#3301)

Co-authored-by: MichaelFiber <[email protected]>

* Revert "Disable UBSAN in zig builds. (#3292)" (#3303)

This reverts commit a316f9e.

Issue #1891 was fixed again, so this is no longer needed.

* rtextures: Fix ImageDraw() source clipping when drawing beyond top left (#3306)

* REVIEWED: `TextToPascal()` issue when first char is uppercase

* Implement FLAG_WINDOW_RESIZABLE for web (#3305)

Fixes #3231

* Update BINDINGS.md (#3307)

Fix Kaylib binding. Reroute to a new repository.
Binding renamed.

* Update webassembly.yml

* Add claw-raylib to BINDINGS.md (#3310)

* Add SetWindowMaxSize for desktop and web (#3309)

* Add SetWindowMaxSize for desktop and web

* Remove SizeInt and respective adjustments

* Update rtextures.c

* Reviewed parameters for consistency

* Rename windowM* to screenM* (#3312)

* Update BINDINGS.md (#3317)

Update TurboRaylib bindings

* Update rmodels.c

* Update BINDINGS.md with vaiorabbit/raylib-bindings (#3318)

* fixed spelling mistake

* put back parenthesis

* reverted major allignment changes

* reverted parser output changes

* reverted one more indentation change

---------

Co-authored-by: Brian-E <[email protected]>
Co-authored-by: Ray <[email protected]>
Co-authored-by: ubkp <[email protected]>
Co-authored-by: ashn <[email protected]>
Co-authored-by: actondev (Christos) <[email protected]>
Co-authored-by: vitopigno <[email protected]>
Co-authored-by: Asdqwe <[email protected]>
Co-authored-by: Jeffery Myers <[email protected]>
Co-authored-by: Ethan Simpson <[email protected]>
Co-authored-by: Nickolas McDonald <[email protected]>
Co-authored-by: Branimir Ričko <[email protected]>
Co-authored-by: iacore <[email protected]>
Co-authored-by: Ethan Conneely <[email protected]>
Co-authored-by: Johannes Barthelmes <[email protected]>
Co-authored-by: bXi <[email protected]>
Co-authored-by: Ryan Roden-Corrent <[email protected]>
Co-authored-by: Ikko Eltociear Ashimine <[email protected]>
Co-authored-by: SuperUserNameMan <[email protected]>
Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: Dan Vu <[email protected]>
Co-authored-by: Gabriel dos Santos Sanches <[email protected]>
Co-authored-by: Rob Loach <[email protected]>
Co-authored-by: Peter0x44 <[email protected]>
Co-authored-by: Kenta <[email protected]>
Co-authored-by: bohonghuang <[email protected]>
Co-authored-by: turborium <[email protected]>
Co-authored-by: Wilson Silva <[email protected]>
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

Successfully merging this pull request may close these issues.

None yet

3 participants