Skip to content

[rcore] Add basic support for scancodes#4481

Closed
JeffM2501 wants to merge 9 commits into
raysan5:masterfrom
JeffM2501:scancodes
Closed

[rcore] Add basic support for scancodes#4481
JeffM2501 wants to merge 9 commits into
raysan5:masterfrom
JeffM2501:scancodes

Conversation

@JeffM2501

Copy link
Copy Markdown
Contributor

Currently raylib does not expose the scancode data for keyboard input received from the platform. This makes it VERY hard to build keyboard bindings that work with different keyboard mappings and localizations. They KeyboardKey enum is just the physical keys and does not take the keyboard mapping into account. For most game input this is fine, as you want the physical key, but there are use cases where you need local mapping of non-text keys.

GetCharPressed handles the mapping, but only for printable characters.

Any user that wants the 'logical' key that is provided by the keyboard mapping as no way to get this data.
The data was passed to the keyboard input functions of most platforms, but the raylib key system has no place to store it.
In SDL this scancode is the 'virtual key'

This PR adds GetKeyPressedPro that takes an optional scancode to fill out, allowing people to see the localized key for each event.
Platforms that don't provide a scancode set the code to -1.

I don't know if this should go into 5.5 or if we should discuss the API for the future. This is just the smallest possible change to raylib to expose the data that it's currently ignoring. I am just posting this so it doesn't get lost.

@raysan5

raysan5 commented Nov 11, 2024

Copy link
Copy Markdown
Owner

@JeffM2501 I see the issue but I want to review this change more carefully, waiting after 5.5 release for further discussion.

@JeffM2501

Copy link
Copy Markdown
Contributor Author

@JeffM2501 I see the issue but I want to review this change more carefully, waiting after 5.5 release for further discussion.

Absolutely understandable

@raysan5 raysan5 changed the title [rInput] Add basic support for scancodes [rcore] Add basic support for scancodes Nov 16, 2024
Comment thread src/rcore.c Outdated
//----------------------------------------------------------------------------------
typedef struct { int x; int y; } Point;
typedef struct { unsigned int width; unsigned int height; } Size;
typedef struct { int keycode; int scancode; } KeyCodes;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'd call this struct KeyInfo to avoid confusion with keycode

Comment thread src/raylib.h Outdated
RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed
RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
RLAPI int GetKeyPressedPro(int* scanCode); // Get key pressed (keycode), and optional scancode, call it multiple times for keys queued, returns 0 when the queue is empty

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

As per raylib design, I try to minimize return-pointers when possible. I prefer a int GetKeyPressedRaw(void) function to note the raw nature (scancode) of returned key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The problem with making a function that just returns the scan code is that this pulls from the events. Calling that function will eat the event and prevent you from beeing able to get the Keyboard Key too.
There may be cases where the user wants both (such as for a "press a key" control config dialog), they need the KeyboardKey to use later for polling, but the scancode to be able to show the mapped key name.

The other option is to return the KeyInfo structure by value.

Comment thread src/platforms/rcore_android.c Outdated

CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount].keycode = key;
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount].scancode = -1;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

It seems scancode can be read with NDK AKeyEvent_getScanCode().

Comment thread src/rcore.c
// Get the last key pressed
int GetKeyPressed(void)
{
return GetKeyPressedPro(NULL);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Considering GetKeyPressed() is very short, I think code lines can be "duplicated" for GetKeyPressedRaw().

Comment thread src/platforms/rcore_desktop_rgfw.c Outdated
{
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount].keycode = key;
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount].scancode = event->keyCode;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'm curious, why key scancode is actually event->keyCode? @ColleagueRiley

@JeffM2501

Copy link
Copy Markdown
Contributor Author

Per our discussion on discord.
GLFW calls the KeyboardKey value "key" and the mapped value ScanCode
SDL calls the KeyboardKey value scancode, and the mapped value the "SDL virtual keysym" https://wiki.libsdl.org/SDL2/SDL_Keysym
This is very confusing.
I think we should come up with our own names for these things and let the platform map as needed.

JeffM2501 and others added 3 commits December 11, 2024 15:59
use the correct value for virtual key from sdl.
…nflicting definitions of scancode in GFLW and SDL.

@orcmid orcmid left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the pair struct is valuable. mappedcode seems awkward (and I wonder about the absence of camelCase).

For me, I think of it as scanCode versus keyTop. And of course, that would normally depend on a keyboard binding, with a QWERTY ANSI keyboard the default. So that's murky too, since shift-state is also reflected. On the other hand, it might be more helpful for people to understand at least the default situation. Not proposing anything, just musing about the awkwardness of this situation.

@ColleagueRiley

Copy link
Copy Markdown
Contributor

@raysan5 After looking into GLFW's code with Jeff, I found that GLFW only supports the use of scancodes, but not keycodes.

The scancode data is the source API's scancode, where as the key data is GLFW's API scancode.

@JeffM2501

Copy link
Copy Markdown
Contributor Author

Yes, after good discussion and research, it has been shown that GLFW doesn't support a mapped value, so this entire PR is pointless while GLTF is the default backend. I am going to close it and open a discussion where we can talk about what we want raylib to expose and come up with use cases.

@JeffM2501 JeffM2501 closed this Dec 12, 2024
@orcmid

orcmid commented Dec 12, 2024

Copy link
Copy Markdown
Contributor

I think the pair struct is valuable. mappedcode seems awkward (and I wonder about the absence of camelCase).

For me, I think of it as scanCode versus keyTop. And of course, that would normally depend on a keyboard binding, with a QWERTY ANSI keyboard the default. So that's murky too, since shift-state is also reflected. On the other hand, it might be more helpful for people to understand at least the default situation. Not proposing anything, just musing about the awkwardness of this situation.

@JeffM2501
I await the Discussion to be opened. Meanwhile, I keep obsessing about this complicated situation. I think there are 2+ cases and tensions with an application's usability (UX) and internationalization (i18n). In particular, dialogs that specify keypresses for actions (e.g., the famous WASD on US-ANSI keyboards and similar ones based on Roman alphabets). Accessibility (a11y) might also factor in, along with IME.

I am tempted to suggest that "mapped code" should be "keyedChar" (depending on type, since might not be u8, although "keyedGlyph" might be more accurate but not so understandable) that provides coordination with what an user sees themselves keying and what the application recognizes as keyed if reflected in a message and especially in an action.

Somehow, the default case should just work in alignment with the original impetus for raylib (namely BGI) and the idea of simplicity.

The question then becomes how to address some of these more-expanded use cases and computer configurations while being as simple as possible (but no simpler) in the main and in line with raylib as a learning instrument for graphical applications.

PS: Some of us might be old enough to recall that WASD as arrow keys was introduced with teletype keyboards and early video consoles. It was used in text editors and word processors before there were PCs and Wintel (but Unix). I am unclear about when it became a typical keyboard-mouse mapping for interactive games.

PPS: I don't think all of this can or should be handled under the covers by raylib. However, it would be great to have a reliable way to graft on additional facilities that work smoothly as raylib adjuncts. So raylib should enable without getting in the way while providing default paths that work as always.

@JeffM2501

Copy link
Copy Markdown
Contributor Author

I have created a discussion topic here
#4595

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.

4 participants