[core] Splitting rcore by platform into submodules

Issue description
As part of my experimenting in pr #3311 to divide rcore into submodules, one of the things I found was that the CoreData structure adds a lot of complexity to that endeavor and MAY benefit from being split up as well.  I believe it may benefit because the current CoreData structure can be fairly difficult to understand with the large number of preprocessor directives within the struct itself. This is largely done to accommodate the many different target platforms.  But if rcore is divided into different submodules based on platforms there is an opportunity to increase clarity.
Here are a couple of initial ideas for approaches:

Maintain a single instance of CoreData but have CoreData only contain data that all submodules use so that it is a simpler struct with no preprocessor directives.  A single CORE instance would be defined extern in rcore.h, defined in rcore.c, and accessed from rcore.c and all the submodules.  In addition to this each submodule would have a small CoreData like struct of its own, i.e. DesktopData, WebData, etc. The data that is currently in CoreData that is specific to an submodule would be moved to the data struct in that submodule.  Each struct definition would become much more legible because it wouldn't be full of preprocessor directives but there would be more structs overall and they'd be more spread out instead of centralized in rcore.

Another option could be to have the CoreData struct defined entirely within a submodule specific header file so that each submodule has a complete CoreData struct and rcore.c can include a specific one based on the PLATFORM variable. There'd be more duplication but fewer structs and data would not be divided across multiple structs. Any changes to the data in CoreData that is used by all submodules would require applying the change to each submodule.

Personally I'm leaning towards the first option but am interested in what others think.
Environment
Experiments are being coded in Ubuntu 23.04 and leverage github actions to attempt to run build steps for all platforms.
Code Example
#3311

Under approach 1, what would happen to a member that is used, lets say, by PLATFORM_DESKTOP and PLATFORM_WEB but not PLATFORM_ANDROID nor PLATFORM_DRM.
Would it be under rcore?
Or not in rcore but duplicated on PLATFORM_DESKTOP and on PLATFORM_WEB?

I think both approaches have pros and cons.

1 keeps a common unified structure for all platforms with just "some" static additional variables per module (duplicated if required, @ubkp) but makes it more difficult to create multi-windows applications in case it was needed, because of those same custom variables, some pieces of data are spread around.
2 allows more customization per platform and makes the modules more self-contained per platform, but also increases the complexity dealing with multiple duplicated structs, if a change is needed, it should be maybe propagated to all platforms, for example, recently some new variables were added.

I think the best option could be 1, despite the cons. concerns. I think the number of custom variables is not that big and it should be easier to manage if well organized and documented in the code.
In an ideal scenario, the "extra" required variables could be, maybe, removed or integrated in some way into the main CoreData struct... Actually, that's another possibility, just keep everything in CoreData independently of the platform, beeing used or not. Probably the overload won't be that dramatic...

 Probably the overload won't be that dramatic...

This would be excellent. Would make a lot simpler for anyone that want/need to extend it. I'd vote for this one.

Actually, that's another possibility, just keep everything in CoreData independently of the platform, beeing used or not. Probably the overload won't be that dramatic...

I like that. It would be super clear. And a shared data structure would probably guide platform specific development to re-use rather than reinvent since every platform would have access to all the data structure anyway.
I hadn't considered multiple windows when I was thinking through it so the approach I was leaning towards before would probably need a lot of work to handle that sanely. And it would lose a lot of clarity.

@michaelfiber @ubkp I've been thinking about the best approach for code organization and I got to the conclusion that an option to avoid breaking all raylib current build systems (and potentially many bindings or user codebases), it could be a good idea to just keep the rcore.c as the base module, containing all common functions BUT also the inclusion of the required submodules:
// rcore.c

// required data types and variables

#if defined(PLATFORM_DESKTOP)
    #include "rcore_desktop.c"
#elif defined(PLATFORM_WEB)
    #include "rcore_web.c"
#elif defined(PLATFOM_DRM)
    #include "rcore_drm.c"
#elif defined(PLATFOM_ANDROID)
    #include "rcore_android.c"
#else
    // Software rendering backend, user needs to provide buffer ;)
#endif

// Common funtions to all platforms

From an academic point of view it could be ugly but in practice it works very well.

@michaelfiber @ubkp I'd also like to accelerate the development of this improvement, considering the latest events on the gamedev industry I think it could be beneficial for raylib in multiple ways, for example to allow other contributors to hook additional platforms in an easy way; at this moment I know is quite scary to look at rcore.
Please, let me know if you could help me with this big redesign!

my idea is to just keep the rcore.c as the base module, containing all common functions BUT also the inclusion of the required submodules

In that scenario, for example, IsWindowMinimized()(L1154-L1160), would it be under rcore.c with its #ifdefs? Or not in rcore.c but duplicated on rcore_desktop.c and rcore_web.c?I ask this because, if it's under rcore.c, then I don't think much would change. rcore.c would still have a considerable amount of #ifdefs, thus harder to track. I guess most functions would fall under that case.

#if defined(PLATFORM_DESKTOP)
#include "rcore_desktop.c"
#elif

Please correct me if I'm wrong (and I'm probably wrong), but I was under the impression that this way of including would be a bad idea (refs: 1, 2, 3).

for example to allow other contributors to hook additional platforms in an easy way;

I'd say the only (actual) missing platform would be iOS. IMHO, I don't think we'd be seeing aditional (e.g.: consoles) platforms even if the conditions were right because of the SDKs and NDAs. Just as a reference, quoting the Godot documentation on a similar subject:

The reason other consoles are not officially supported are:

To develop for consoles, one must be licensed as a company. As an open source project, Godot has no legal structure to provide console ports.

Console SDKs are secret and covered by non-disclosure agreements. Even if we could get access to them, we could not publish the platform-specific code under an open source license.

I admit I'm having a hard time visualizing it all (separation, building, etc). Would it be a good idea to test it first in a sort of very minimal skeleton/prototype with just one or two structs/functions inside just to see what works or not?

@michaelfiber @ubkp I've been thinking about the best approach for code organization and I got to the conclusion that avoiding breaking all raylib current build systems (and potentially many bindings or user codebases) is the best option, my idea is to just keep the rcore.c as the base module, containing all common functions BUT also the inclusion of the required submodules:
// rcore.c

// Required data types and variables

#if defined(PLATFORM_DESKTOP)
    #include "rcore_desktop.c"
#elif defined(PLATFORM_WEB)
    #include "rcore_web.c"
#elif defined(PLATFOM_DRM)
    #include "rcore_drm.c"
#elif defined(PLATFOM_ANDROID)
    #include "rcore_android.c"
#else
    // Software rendering backend, user needs to provide buffer ;)
#endif

// Common functions to all platforms

From an academic point of view it could be ugly but in practice it works very well.

Doing it this way feels wrong but I completely understand not wanting to break builds.  Updating the Makefile was easy but I don't know about updating the others.  Right now for testing I'm going to leave the Makefile change and then as I progress through this maybe I'll spot another way that doesn't feel so wrong? With the position of raylib as a great tool for education I'd hate to include something that would have a comment like // You shouldn't do this
Also for the CoreData I realized that if all the data is always there without preprocessor directives then it either needs all dependencies included no matter that target platform OR a lot of void pointers that will have to be cast each time in the platform specific rcore files.
Right now I am leaving the #if defined(PLATFORM_*) directives in the struct as I split out the rest of the functions.  The CoreData structure doesn't get any more difficult to read than it did before but it maintains its very difficult to read directives.  Another less disruptive approach may be a simple refactor to move platform specific stuff so there's just one directive per platform in CoreData.  CORE->handle would become CORE->desktop->handle for instance.  It does mean some repeated data structures between platforms but I think the readability would increase dramatically.

@ubkp here the answers for your questions:

In those cases the function would be duplicated for all platforms requiring it.

It's not recommended and probably bad practice from an academic point of view, still, it can be used and it's really handy. Actually raylib uses that approach for all its external libraries, #define XXXX_IMPLEMENTATION does exactly that.

Yes, most noticeable missing platform is PLATFORM_IOS, maybe PLATFORM_SOFTWARE could also be an option... BUT this structure opens the door to the addition of console platforms (by licensed users) in an easier way with minimal raylib modifications. Console homebrew platforms could also follow this same pattern.

Yes, it's a very big change in structure. I don't fully visualize it at the moment but I think it could work.

Completely agree. Still considering if moving the platform-specific parts from CoreData structure is a better approach, actually CoreData was created quite recently for organization (as a struct of structs), not long ago it was just a bunch of global variables.

Doing it this way feels wrong but I completely understand not wanting to break builds.

@michaelfiber I know, it feels wrong... but it actually works like a charm for this kind of situations.

@raysan5 Ok, I can try that out.

EDIT: Copying the info from wishlist for reference:
* [ ]  **REDESIGN: Module  subdivision**. This module has grown a lot with every new supported platform (~7000 loc), at some point it could be divided into separate modules. Two possible approaches:

  * Divide by platform:

    * `rcore_desktop.c`  - `PLATFORM_DESKTOP` (Windows, Linux, macOS)
    * `rcore_android.c` - `PLATFORM_ANDROID`
    * `rcore_native.c` - `PLATFORM_DRM`/`PLATFORM_RPI`
    * `rcore_web.c` - `PLATFORM_WEB`
  * Divide by technology

    * `rcore_glfw.c` - GLFW library based
    * `rcore_sdl.c` -  SDL library based
    * `rcore_native.c` - Native implementation

This is not an easy task, still deciding the proper approach for it. There are 45 functions depending on ~100 GLFW functions, those 45 functions should be reproduced separately for the different platforms/technologies and exposed through the same common API.

I'll probably just go function by function through rcore and move the functions that have platform_specific logic.  That will probably align with the list of functions that reference glfw but I'm not sure.  Also If you are keeping a list then SetWindowFocused should be on it too.

Immediately as I make this transition I see the opportunity to add some simple javascript functions to the default HTML templates for emscripten that would help with things like reading the clipboard and disabling the cursor without having the ID of the canvas element hard coded into raylib. That makes me think this submodule approach might be a good one. It's much easier to check at a glance how complete each implementation is.

@michaelfiber If you need help with anything, please let me know.

@michaelfiber thank you very much for this big effort! Undoubtely it opens the door to many per-platform improvements.
This is a lot of work, please, let me and @ubkp help with it.
I set a separate branch for it to keep merging the changes: https://github.com/raysan5/raylib/tree/rcore_platform_split
We can divide the functions to port in chunks between us.
Also, I'm locking any change in rcore module for now, at least until we get  a functional version and we can validate if it's a good line to follow for raylib (I'm pretty convinced of it!).

I'm doing a basic split on the platform specific preprocessor directives so it's actually very easy.  But once its done the real work of making sure each submodule is correct and builds will be more time consuming I think and that'll be very easy to divvy up.
I should be done splitting rcore today and maybe after that we can share going through the submodules?

@raysan5 I changed PR #3311 to target rcore_platform_split and finished moving the listed functions.  There were a couple of functions not on the list that I moved because their logic was highly platform dependent.  I have a feeling more such functions are there in rcore but I just haven't had the chance to go through every function yet.  When a function like that is found it needs to be moved from rcore to all submodules at the same time. So that might create logistical issues as we work on this.
I did all my work on Linux and it shows as the linux builds are the only ones working at this time.  The windows build has been succeeding every time I push even though it was definitely actually failing so that needs more than just the github action to verify if it is working at all.
I think this is a good place to start divvying up the work since different people can work on different submodules simuiltaneously and the only real friction will be when changes need to be made to rcore.c or rcore.h.
I'm going to be away from my computer for a few days now but when I get back I can continue to hack away at some of this.  I would probably start working specifically on PLATFORM_DRM since I have some experience with it and a variety of devices already running raylib projects to test with.

@michaelfiber Thank you very much for the big amount work put into this improvement!
I'm merging it right now and reviewing Windows build in the following days! Thanks!

@raysan5 @michaelfiber I can review PLATFORM_WEB (it's the one I got more experience with).

@raysan5 @michaelfiber I have cloned the branch and my Windows x64 build using VC/C++ fails with a fatal error in compiling rcore.c.
 rcore_desktop.c(3) fatal error C1083: Cannot open inlude file: 'rcore.h': No such file or directory

Seems to be the case.

@orcmid The previous version had rcore.h (https://github.com/raysan5/raylib/commit/f27454c57ae252808e03b5a0da074838c305357b) but @raysan5 moved its content to rcore.c (https://github.com/raysan5/raylib/commit/71a12171f768eb25053ef908732b4ce8fdf802f7). Likely still cleaning up after the change and missed it on rcore_desktop.c (L3).

@raysan5 Would it be a bad idea to move rcore.h's contents to raylib.h?

@ubkp I prefer to avoid that, it will add too much uneeded content in raylib.h and probably a lot of confusion that use raylib.h as their reference cheatsheet. rcore.h is ok.

@raysan5 I moved raymath.h out of rcore.h because it was clobbering the #define RAYMATH_IMPLEMENTATION directive. Submitted as pr #3331
That fixed my build issues across platform related to not being able to find raymath functions.

Please note that I pushed a commit to rcore (https://github.com/raysan5/raylib/commit/a2b3b1ebe43cdf394b49f901cbaedb2c87959168). I'm afraid it was an issue that could cause a stack overflow in several platforms when using CompressData() function, it was actually breaking some of my tools in PLATFORM_WEB because emscripted sets a maximum size for stack by default to 65KB.

@ubkp did you encounter this as well in your work?

@michaelfiber Not yet. Testing PLATFORM_WEB is going really smoothly here. After fixing the initial compiling errors I jumped to test the examples and (aside from a few that are actually not working even on current master branch) just found two examples that needed review.
I'm still going through all functions but, so far, everything is working really well. You did an incredible job on the split. :+1:

@raysan5 @michaelfiber Sorry to ask this again, but, just to be absolutely sure, for example, in this case (rcore.c#L2124-L2132):
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
    return (int)CORE.Input.Touch.position[0].x;
#else   // PLATFORM_DESKTOP, PLATFORM_DRM
    return GetMouseX();
#endif
}

Should this be removed from rcore.c and moved to rcore_android.c, rcore_web.c, rcore_desktop.c and rcore_drm.c?
If yes, would you like me to do it for rcore_desktop.c and rcore_android.c as well while I'm at it? And also for the others functions in similar situation?

@raysan5 @michaelfiber Sorry to ask this again, but, just to be absolutely sure, for example, in this case (rcore.c#L2124-L2132):
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
    return (int)CORE.Input.Touch.position[0].x;
#else   // PLATFORM_DESKTOP, PLATFORM_DRM
    return GetMouseX();
#endif
}

Should this be removed from rcore.c and moved to rcore_android.c, rcore_web.c, rcore_desktop.c and rcore_drm.c?
If yes, would you like me to do it for rcore_desktop.c and rcore_android.c as well while I'm at it? And also for the others functions in similar situation?

I think it should be split out. But I guess it depends on the end goal. Is the goal to eliminate all the preprocessor stuff related to platform from rcore.c other than the part where the submodule gets included?

I agree. Otherwise we end up with a 50/50 mix of both, which kind of defeats the purpose of the split.

Should this be removed from rcore.c and moved to rcore_android.c, rcore_web.c, rcore_desktop.c and rcore_drm.c?

Yes.

I think it should be split out. But I guess it depends on the end goal. Is the goal to eliminate all the preprocessor stuff related to platform from rcore.c other than the part where the submodule gets included?

Yes, we want to avoid mixing both.

@michaelfiber @raysan5 I believe I've finished reviewing PLATFORM_WEB and PLATFORM_DESKTOP. While going through the functions I also reviewed them for PLATFORM_ANDROID, but couldn't test it. I've updated the modules and functions tables on #3339 in case it's needed. Also finished the PR #3345 (batch 5), which is ready for merging. :+1:

@ubkp Thank you very much for all your work on this new project! I can continue from this point and double check everything.

@raysan5 Note: the functions I moved on the batches from rcore.c to the submodules I just left commented instead of deleting them: L1940-L1947, L2109-L2122, L2124-L2132, L2134-L2142, L2144-L2162, L2449-L2721. They can safely be removed after your review.

@ubkp Ok, thanks for letting me know!

That leaves PLATFORM_ANDROID. In theory I can get that set up and test out building the examples and such. But probably not until the weekend at the earliest. Whichever one of us can get to it first should just make another issue for tracking status and informing the others that testing is underway.  Hopefully getting the android dev side of it set up isn't too painful.

@michaelfiber @raysan5
While I went through #3339 I also checked the functions for rcore_android.c. Unless I missed something, I think everything is there.
Following these wiki instructions and after the #3360 small fix, I was able to successfully compile raylib for PLATFORM_ANDROID for ARM and x86 for both 32bit and 64bit.
Unfortunately, I could not compile the examples automatically using make (I don't think the Makefile supports that). But I was able to successfully compile a core_basic_window.c example manually by using the build script from the wiki.
However, the compiled apk requires Android 6+, and my device is stuck on 5.1.1. So I was not able to run it to confirm function. This was as far as I could get. But I'd say there's a pretty good chance it's working.

I have hit a nonstop stream of issues trying to build them for Android.  I think because of problem with my distro that is going to require a reinstall. A few other things are broken too.  So I won't be able to test the android stuff any time soon.  @raysan5 @ubkp not sure what the best way to test will be.  @ubkp If you can send me the APK I can test it I just can't seem to get building to work right right now.

@michaelfiber I didn't keep the vm where I compiled it. But I'll rebuild it and try to rollback the Android version to one that matches 5.1.1 so I can test it here. Don't worry about it. :+1:

Update: I managed to setup the environment again and successfully compiled raylib for PLATFORM_ANDROID without issues.
However, the apk file generated was actually malformed. This does not appear to be related to raylib but to the compiling setup of the program/game (confirmed this case because even a simple int main(void) { return 0; } is having linking issues).
I'm investigating further.

@michaelfiber @raysan5
Update: I'm going through all examples and things are looking pretty good. Although Waydroid is not perfect, it appears to be enough for confirming function. I should have all tested in about one to two days.

@michaelfiber @raysan5

I've finished testing PLATFORM_ANDROID. The full test logs and results were posted on:
#3371.

Basically everything is working. The only issues I encountered appear to be related to Waydroid. In summary:

:x: Mouse buttons are not working on raylib on Waydroid (they appear to be stuck on pressed).
:x: Gestures are not working on Waydroid.

Thus, the mouse presses are the only thing I couldn't really test. So I compiled the examples/textures/textures_mouse_painting.c for Android 6+ bellow:

textures_mouse_painting.zip

Could any of you please test it? If it works, then I believe PLATFORM_ANDROID is ready.

@ubkp Sorry it took so long! I finally got to test this out.
It works on Android 12.  Very nice seeing the Raylib logo appear on the install dialog and it runs fine EXCEPT it cannot save images. The save appears to succeed but the file doesn't end up anywhere.  I assume there are a ton of permission things that have to be set up to allow stuff like that so my guess is this is mostly indicative of how annoying it is to develop for Android
But the actual picking of colors and drawing works fine.

@michaelfiber That's excellent, thanks for testing! Yeah, Android is a nightmare.
Well guys, I guess this is it then, everything looks ready. :+1:

@ubkp @michaelfiber do you think it's about time to merge this redesign into master? It's a bit scary for me but there are MANY rcore issues waiting and probably we shouldn't wait way longer...
I've been using rcore_platform_split branch for my tools development on desktop and web for a couple of weeks and everything seems to work ok.

@raysan5 I've tested/reviewed everything I could multiple times. The only systems I couldn't test was Windows and MacOS because I have neither. But if something slip through, shouldn't be anything major, otherwise we probably would have seen it by now happening on the examples.
I think it's ready for merge.
Fail-safe: Just in case, before merging, could do a point release with current master branch. Or just add tag on the repository in case it needs reverting.

@michaelfiber @ubkp Just reviewed all submodules, mostly formatting and code-gardening. I'm creating a tag, merging the branch and we can continue from there.

@raysan5 I believe you'll have to reapply this commit<PHONE_NUMBER>849b1579db962f30e42fb982400c7e change on rcore.c.
Basically changing LINE 1137 on rcore.c from:
float aspect = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;

To (as per<PHONE_NUMBER>849b1579db962f30e42fb982400c7e):
double aspect = ((double)width/(double)height);

@ubkp thanks! just reviewed it!

@ubkp @michaelfiber Hi! Following with the redesign, I moved all the platform-specific data to separate PlatformData structures.
I did a quick test for PLATFORM_DESKTOP and PLATFORM_WEB and everything seems to work, please, could you try PLATFORM_DRM and PLATFORM_ANDROID?

@raysan5 Ok, I'll check PLATFORM_ANDROID.

I've done some more review and code organization, simplified TakeScreenshot() and moved to rcore.c.
I created rcore_custom.c module as a template for new platform implementations. Considering a platform_sdl.c at the moment...
Now I'm checking the functions moved to separate platforms, I think some of them could be probably moved back to rcore.c. For example, some of the input-based functions that just return a state from CORE.Input could be probably moved and the required state for every platform forced by PollInputEvents().

@ubkp @michaelfiber Hi! Following with the redesign, I moved all the platform-specific data to separate PlatformData structures.
I did a quick test for PLATFORM_DESKTOP and PLATFORM_WEB and everything seems to work, please, could you try PLATFORM_DRM and PLATFORM_ANDROID?

I did quick tests of PLATFORM_DRM and couldn't find any issues.

Currently the PLATFORM_ANDROID's building is very manual, which is not viable for recurrent testing. While the main setup is not that much of a problem, building each example is.
So I'm trying to work out a setup here that would make that testing a bit more practical. This may delay me a day or two tho.

WAAAA increíble una de las cosas que mas quería hacer ❤

@ubkp @michaelfiber I continue with the platforms review and code cleaning and organization, to simplify/document the addition of new platforms as much as possible. Already moved some function from platform-specific code to rcore.c and I think some more can be moved with some review. Here a list with functions that I think could be moved:

int GetGamepadAxisCount(int gamepad)

For most platforms just returns CORE.Input.Gamepad.axisCount but for PLATFORM_DRM that queries axisCount with a ioctl(), could this call be moved to InitGamepad() or GamepadThread() and just fill CORE.Input.Gamepad.axisCount?

const char *GetGamepadName(int gamepad)

Just reviewed implementation for PLATFORM_DESKTOP to use CORE.Input.Gamepad.name[id], similar to previous function, probably a similar implementation can be used for PLATFORM_DRM

int GetMouseX(void)
int GetMouseY(void)
Vector2 GetMousePosition(void)
float GetMouseWheelMove(void)

All those functions have same implementation for most platforms, only PLATFORM_ANDROID returns CORE.Input.Touch.position[0], I'm sure that value could be feed somewhere else to mouse equivalent.

int GetTouchX(void)
int GetTouchY(void)
Vector2 GetTouchPosition(int index)

Similar to previous case, those functions should always return CORE.Input.Touch.position[0] and be mapped to CORE.Input.Mouse.currentPosition as required.
Please, could you help with the some of those?

@ubkp @michaelfiber I continue with the platforms review and code cleaning and organization, to simplify/document the addition of new platforms as much as possible. Already moved some function from platform-specific code to rcore.c and I think some more can be moved with some review. Here a list with functions that I think could be moved:
* `int GetGamepadAxisCount(int gamepad)`

For most platforms just returns CORE.Input.Gamepad.axisCount but for PLATFORM_DRM that queries axisCount with a ioctl(), could this call be moved to InitGamepad() or GamepadThread() and just fill CORE.Input.Gamepad.axisCount?

That makes sense, I can work on that tonight (in about 12 hours).

* `const char *GetGamepadName(int gamepad)`

Just reviewed implementation for PLATFORM_DESKTOP to use CORE.Input.Gamepad.name[id], similar to previous function, probably a similar implementation can be used for PLATFORM_DRM

This seems like a straight forward thing to fix as well.  How should raylib react if the plugged in gamepad changes while the program is running?  Should it just automatically pick up the new pad and start using it?  If so then the name and the axis count should be polled regularly.  If not, just the axis count should be polled regularly (I have a couple gamepads that let you alter the axis count on the fly with on-gamepad buttons).

* `int GetMouseX(void)`

* `int GetMouseY(void)`

* `Vector2 GetMousePosition(void)`

* `float GetMouseWheelMove(void)`

All those functions have same implementation for most platforms, only PLATFORM_ANDROID returns CORE.Input.Touch.position[0], I'm sure that value could be feed somewhere else to mouse equivalent.
* `int GetTouchX(void)`

* `int GetTouchY(void)`

* `Vector2 GetTouchPosition(int index)`

Similar to previous case, those functions should always return CORE.Input.Touch.position[0] and be mapped to CORE.Input.Mouse.currentPosition as required.
Please, could you help with the some of those?

If this is still up for grabs after I'm done with the DRM changes I can take a look.

@raysan5 @michaelfiber I apologize for being late on the PLATFORM_ANDROID testing. Although compiling is no problem (reference), testing is a challenge since my device is too old and Android is not easy to emulate. I'm still working on it (trying Bless OS right now).

If this is still up for grabs after I'm done with the DRM changes I can take a look.

@michaelfiber Please do. Mouse/touch is the one thing waydroid has trouble with, so I can't reliably test it yet.

The rcore_custom is great, I have less work to update, although I think that some functions like LoadFontDefault should not be stopped and I also think that it would be good to implement some funcs like:
RLAPI void MouseButtonCallback(int button, int action, int mods);
RLAPI void MouseCursorPosCallback(double x, double y);
RLAPI void MouseScrollCallback(double xoffset, double yoffset);
RLAPI void WindowSizeCallback(int width, int height);
RLAPI void KeyCallback(int key, int scancode, int action, int mods);

The idea of this is that an event system can fill it in without a problem. Thanks Thanks Thanks Thanks.

How should raylib react if the plugged in gamepad changes while the program is running? Should it just automatically pick up the new pad and start using it? If so then the name and the axis count should be polled regularly. If not, just the axis count should be polled regularly (I have a couple gamepads that let you alter the axis count on the fly with on-gamepad buttons).

@michaelfiber This is a good question, I think any solution you choose would be a good solution, with its pros and cons. Polling regularly is more costly but probably more convenient for users while polling only on initialization is way less costly and probably most user will never change gamepads. In any case, the solution you choose is good.

I apologize for being late on the PLATFORM_ANDROID testing. Although compiling is no problem (https://github.com/raysan5/raylib/issues/3371#issuecomment-1745365670), testing is a challenge since my device is too old and Android is not easy to emulate. I'm still working on it (trying Bless OS right now).

@ubkp No worries at all! I'm aware PLATFORM_ANDROID is quite a pain, it's the most different platform from the list and testing/debugging is pretty complex.

I think that some functions like LoadFontDefault should not be stopped and I also think that it would be good to implement some funcs like...

@hbiblia I don't understand what you mean about LoadFontDefault(), about the proposed functions, raylib approach to input polling is different than other libraries, no plans to implement callbacks.

I mean rcore_custom.c is not loading LoadFontDefault(); but it is calling UnloadFontDefault();.

core_custom_frame_control.c  tiene un parpadeo
https://github.com/raysan5/raylib/assets/1939353/68b56f49-b603-44cb-b84b-ae78096732b6

@michaelfiber This is a good question, I think any solution you choose would be a good solution, with its pros and cons. Polling regularly is more costly but probably more convenient for users while polling only on initialization is way less costly and probably most user will never change gamepads. In any case, the solution you choose is good.

I realized that for now it makes sense to just get the axis count once because to do it in the gamepad update thread creates other problems because of race conditions.  I really want to spend some time updating the input system for PLATFORM_DRM anyway. I think the platform has come along enough to start targeting /dev/input/by-id instead of just /dev/input since then we get a nice easy list of devices with mouse, kbd, joystick at the end of the link to identify how to handle it.

@raysan5 @michaelfiber Some updates:

I managed to setup another Android testing environment using qemu/kvm/virgl and Bliss OS 14. Unfortunately it had the exactly same issues Waydroid had with touch gestures and mouse presses.

I started digging and found out that those issues are very common on games. Mostly happening to users trying to run Android games emulated on PC with a mouse instead of a touchscreen.

My best guess is that it's related to how Android handles mouse input and real touch input internally depending on context (Native, OpenGL, Vulkan, etc). Games touch usually don't work emulated. But regular apps touch (that mostly use the Android's view logic) usually work emulated.

My last attempt was trying again the Android Studio. But it's borderline on the limits of my hardware and is something I have almost no experience with. I couldn't get anywhere with the Virtual Device Manager. It will take me some time to learn how to do something there.

So I'm somewhat limited on what I can test on Android. If it's related to mouse/touch/gestures, there's not much I can do right now. Anything else I can probably make work. Really sorry guys.

Just reviewed Mouse and Touch functions, easier than expected! Having the platforms splitted and having a generic PollInputEvents() really benefits those improvements!

Here the current list with the platform-specific functions, as expected most of the functions are window/display/monitor related, that's probably the element with more differences between platforms:

Window and graphics device:

void InitWindow(int width, int height, const char *title)
void CloseWindow(void)
bool WindowShouldClose(void)
bool IsWindowHidden(void)
bool IsWindowMinimized(void)
bool IsWindowMaximized(void)
bool IsWindowFocused(void)
bool IsWindowResized(void)
void ToggleFullscreen(void)
void MaximizeWindow(void)
void MinimizeWindow(void)
void RestoreWindow(void)
void ToggleBorderlessWindowed(void)
void SetWindowState(unsigned int flags)
void ClearWindowState(unsigned int flags)
void SetWindowIcon(Image image)
void SetWindowIcons(Image *images, int count)
void SetWindowTitle(const char *title)
void SetWindowPosition(int x, int y)
void SetWindowMonitor(int monitor)
void SetWindowMinSize(int width, int height)
void SetWindowMaxSize(int width, int height)
void SetWindowSize(int width, int height)
void SetWindowOpacity(float opacity)
void SetWindowFocused(void)
void *GetWindowHandle(void)
int GetMonitorCount(void)
int GetCurrentMonitor(void)
Vector2 GetMonitorPosition(int monitor)
int GetMonitorWidth(int monitor)
int GetMonitorHeight(int monitor)
int GetMonitorPhysicalWidth(int monitor)
int GetMonitorPhysicalHeight(int monitor)
int GetMonitorRefreshRate(int monitor)
const char *GetMonitorName(int monitor)
Vector2 GetWindowPosition(void)
Vector2 GetWindowScaleDPI(void)
void SetClipboardText(const char *text)
const char *GetClipboardText(void)
void ShowCursor(void)
void HideCursor(void)
void EnableCursor(void)
void DisableCursor(void)

Custom frame control:

void SwapScreenBuffer(void);
void PollInputEvents(void);
void WaitTime(double seconds);

Timming

double GetTime(void)

Misc

void OpenURL(const char *url)

Input Handling: Gamepad

int SetGamepadMappings(const char *mappings)

Input Handling: Mouse

void SetMousePosition(int x, int y)
void SetMouseCursor(int cursor)

Internal Functions (Graphics)

static bool InitGraphicsDevice(int width, int height)

There is a total of 52 platform-specific functions but probably some of window/monitor related, the ones that check states, can also be made generic for all platforms just setting the states properly on the platform initialization/update code.

On my end, touch input on Android seems to be working as before, no issues to report. Regarding mouse input for Android, I'm unable to test it with my hardware, except possibly with an emulator, but that may not be representative of real device behavior.
https://github.com/raysan5/raylib/assets/90587919/6a1bde49-b35c-4039-9010-3b18a1a7dbc5
(the fact that the view is cut off on the sides is normal; the window isn't initialized with a resolution that matches my device. However, the fact that this "dead" area is the same color as the background seems new; it would normally be black.)

For simplicity I think the idea is to use the first touch as the value of the mouse for the sake of raylib.  Android has mouse input built in and it is well supported throughout the OS but I haven't the slightest idea what supporting it looks like nor do I know how many people actually use it. I've used it a bunch but I do weird things with my phones.  I also regularly use USB gamepads with android. So, until someone really needs it (and is willing to implement it hopefully) using the first touch seems like a straight forward approach.

I also think it's better this way, and no one seems to be requesting it either.
Otherwise, it's simply handled in android/input.h like other inputs.

So, until someone really needs it (and is willing to implement it hopefully) using the first touch seems like a straight forward approach.

That's the reasons for current approach, I don't know anyone using a mouse connected to an Android phone...

I'm currently conducting tests with as many examples as possible, and I just noticed that the Vector2 GetMouseDelta() function (rcore.c) now returns a value on Android, unlike before. The problem is that it seems to consistently return the delta considering the old touch position as always being at {0, 0}.
So, I'm currently writing a small fix just for my tests, and it will only work with the first touch. Would it be a good idea to add the ability to get the delta of touches? Something like Vector2 GetTouchDelta(int id)?

@raysan5 Should axisCount inside CoreData be an array of Ints so that each gamepad can have a different number of axes?  GetGamepadAxisCount takes a gamepad number but then doesn't use it.

Should axisCount inside CoreData be an array of Ints so that each gamepad can have a different number of axes? GetGamepadAxisCount takes a gamepad number but then doesn't use it.

Oh! Sure, it sounds like a bug! I don't know why it was not added before... afaik, all gamepad data is indexed by gamepad.

The problem is that it seems to consistently return the delta considering the previous touch position as always being at {0,0}.
So, I'm currently writing a small fix just for my tests, and it will only work with the first touch. Would it be a good idea to add the ability to get the delta of touches? Something like Vector2 GetTouchDelta(int id)?

@Bigfoot71 Probably not required, I try to avoid adding new features if they are not required in a real use-case scenario. But the mouse delata issue should be fixed on rcore_android.c!

The best solution in your opinion would be for the function to always return {0,0} as before or to return the delta of the first touchdown? (This would require some adjustment to work properly)

I performed some tests on core_custom_frame_control.c in all versions where it was added, starting from version 4.0, and the same issue occurred in all of them. Windows 11 Nvidia GTX 1660 Ti Laptop. OpenGL 3.3
I conducted the test on another PC, and it doesn't work: Windows 11 Intel(R) UHD Graphics 620. OpenGL 3.3
Update test:
The problem is in SwapScreenBuffer().

Other than that, there's still an issue with detecting the double-tap gesture. I say "still" because I've seen another user complain about it on the Android channel on Discord:

@Bigfoot71 I really wish I could help to debug that issue. My best guess is that there's a problem with some value of the GESTURE_DOUBLETAP detection criteria (L277). Possibly one of these:

GESTURES.current being different from GESTURE_NONE.
GESTURES.Touch.tapCounter being smaller than 2.
rgGetCurrentTime() - GESTURES.Touch.eventTime being larger than TAP_TIMEOUT.
rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) being larger than DOUBLETAP_RANGE.

Do you know if is it possible to the TraceLog messages on Android? If yes, adding the following to LINE 275 on rgestures.h would probably show the problem:
TraceLog(LOG_INFO, "--------------------");
TraceLog(LOG_INFO, "GESTURES.current: %i", GESTURES.current);
TraceLog(LOG_INFO, "\nGESTURES.Touch.tapCounter: %i", GESTURES.Touch.tapCounter);
TraceLog(LOG_INFO, "\nGESTURES.Touch.eventTime: %f", GESTURES.Touch.eventTime);
TraceLog(LOG_INFO, "rgGetCurrentTime(): %f", rgGetCurrentTime());
TraceLog(LOG_INFO, "TAP_TIMEOUT: %f", TAP_TIMEOUT);
TraceLog(LOG_INFO, "rgGetCurrentTime() - GESTURES.Touch.eventTime: %f", (rgGetCurrentTime() - GESTURES.Touch.eventTime));
TraceLog(LOG_INFO, "\nDOUBLETAP_RANGE: %f", DOUBLETAP_RANGE);
TraceLog(LOG_INFO, "rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]): %f", (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0])));
TraceLog(LOG_INFO, "--------------------");

@hbiblia Please double check if SUPPORT_CUSTOM_FRAME_CONTROL was enabled during the library compilation. That can be done by uncommenting LINE 70 from config.h. Otherwise, the core_custom_frame_control.c example won't work correctly.

@ubkp This correctly makes it work, thank you!!

Do you know if is it possible to get the TraceLog messages on Android? If yes, adding the following to LINE 275 on rgestures.h would probably show the problem:

Of course, Android logs can be obtained using logcat. Here are the results of the double-tap attempt:
V  New input event: type=2
I  --------------------
I  GESTURES.current: 0
I  GESTURES.Touch.tapCounter: 1
I  GESTURES.Touch.eventTime: 0.000000
I  rgGetCurrentTime(): 9.464040
I  TAP_TIMEOUT: 0.300000
I  rgGetCurrentTime() - GESTURES.Touch.eventTime: 9.464066
I  DOUBLETAP_RANGE: 0.030000
I  rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]): 588.914001
I  --------------------
V  New input event: type=2
V  New input event: type=2
V  New input event: type=2
I  --------------------
I  GESTURES.current: 0
I  GESTURES.Touch.tapCounter: 2
I  GESTURES.Touch.eventTime: 9.464104
I  rgGetCurrentTime(): 9.580643
I  TAP_TIMEOUT: 0.300000
I  rgGetCurrentTime() - GESTURES.Touch.eventTime: 0.116562
I  DOUBLETAP_RANGE: 0.030000
I  rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]): 5.921487
I  --------------------
V  New input event: type=2
V  New input event: type=2

Here's a video of what happened:
https://github.com/raysan5/raylib/assets/90587919/e0cb8bf0-bfb1-4cfb-84ac-cb6a9ee0ff17
And here's a comparison of how it works on PC:
https://github.com/raysan5/raylib/assets/90587919/2e90faa5-e00b-4229-b5fd-04f142354dfa

Now, I'm going to tackle GetMouseDelta() for Android, and I'll take care of the gesture issue afterward. If you have any ideas in the meantime, feel free to share them, and I'll work on implementing them.
Otherwise, you have raymob to easily compile on Android, it's even simpler with Android Studio.

By the way, I unfortunately don't have a controller available. If someone could try this on Android, that would be fantastic!

Regarding the double tap problem on Android, it seems that it is simply a problem of distance detected between the two inputs.
event.position doesn't seem to be normalized in rcore_android.c, which would explain the logs.

@Bigfoot71 That's excellent, great job!

@Bigfoot71 good catch! thanks for the review! feel free to send a PR!

@michaelfiber @ubkp @Bigfoot71 WARNING! Just redesigned InitGraphicsDevice() into InitPlatform() and ClosePlatform() for organization, consistency and coherence reasons.
Main reason for this change is that InitGraphicsDesign() was currently doing many other things:

Initialize support library
Setup window/framebuffer flags
Initialize window/display
Initialize graphic device
Setup platfom callbacks (window, inputs...)
Initialize inputs systems
Initialize OpenGL extensions
Initialize rlgl (buffers and shaders)

I thought it could be a good idea to unify all that into InitPlatform(), this way, not only all platform initialization is unified into a single function (using/updating required CORE data) but also allows to move InitWindow()/CloseWindow() back to rcore.c (still under consideration).
I tested PLATFORM_DESKTOP and it works ok, if you could give a try to the other platforms at some moment it would be great! Thanks!
PD. PLATFORM_ANDROID is a bit special so I kept the InitGraphicsDevice() but I reviewed it to do just that, init graphic device.

@raysan5 Compiled PLATFORM_WEB and PLATFORM_DRM, tested a few examples, everything looks ok there.
Off-topic: for the future, any chance of moving the automation/event-recording system outside rcore?

@raysan5 There was a small error in InitPlatform in rcore_android.c, and I've just submitted a correction here: https://github.com/raysan5/raylib/pull/3415.
I'm also getting another compilation error due to the new header stb_image_resize2.h, still on Android:
raylib/external/stb_image_resize2.h:2422:17: error: initializing 'float16x8_t' (vector of 8 'float16_t' values) with an expression of incompatible type 'int'
    float16x8_t in = vld1q_f16(input);
                ^    ~~~~~~~~~~~~~~~~

What is this new header supposed to be?

for the future, any chance of moving the automation/event-recording system outside rcore?

@ubkp Sure! It's on my TODO list to review all that system, I'll try to allocate some time as soon as possible.

What is this new header supposed to be? (I mean, compared to the old one)

This header is only used for efficient image scaling, using SIMD and other accelerated instructions modesl provided by the CPU, if available on the target platform. In this case it is trying to call a [Arm Neon Intrinsics](https://arm-software.github.io/acle/neon_intrinsics/advsimd.html) instruction: vld1q_f16(). It seems it can be turned off just defining STBIR_NO_AVX and STBIR_NO_AVX2 before including the library.
I think it can be disabled with some flags.

Thank you for the explanation. I just tested building raylib with its Makefile for Android (all architectures), and there were no errors. So the issue seems to be on my end with Android Studio. Good news!
I'll edit this message once I've successfully compiled and tested the project.

@Bigfoot71 It could be an Android Studio issue with its libraries, afaik, Arm Neon functions should be available in most target Android devices nowadays. The benefit of using them could acceletate x4 the image resizing.

@raysan5 That's strange because this part shouldn't be compiled if I follow the logic of the directives, especially not for x86_64.

It's all good, the issue is resolved. It turned out to be missing rules in the CMakeLists.txt of raymob and Android Studio was indicating 'x86_64,' but when I checked the logs myself, the problem was indeed with 'armeabi-v7a'...
Everything is working now! The application launches correctly, and there's nothing to report!

@raysan5 I haven't tried this on other platforms, but on Android, I get these warnings for SetupFramebuffer(), SetupViewport(), InitTimer():
Call to undeclared function 'SetupFramebuffer'; ISO C99 and later do not support implicit function declarations
Call to undeclared function 'SetupViewport'; ISO C99 and later do not support implicit function declarations
Call to undeclared function 'InitTimer'; ISO C99 and later do not support implicit function declarations

Since they are declared and defined in rcore.c and called in rcore_android.c, this doesn't pose any problem except for the warnings.

Also, I noticed a small issue with InitGraphicsDevice() in rcore_android.c, which is supposed to return a bool but returns -1 or 0. Additionally, we don't do anything with its return value when calling it in AndroidCommandCallback(). LINE 869

And there's one more warning, still for rcore_android.c, for int InitPlatform(void) which doesn't return anything at the end of its definition.

I haven't tried this on other platforms, but on Android, I get these warnings for SetupFramebuffer(), SetupViewport(), InitTimer():

@Bigfoot71 Compiled current master branch (2498170) on PLATFORM_DESKTOP, PLATFORM_WEB and PLATFORM_DRM and didn't get those warnings. I guess it's something with rcore_android.c in particular.

@michaelfiber @ubkp @Bigfoot71 WARNING! Just redesigned InitGraphicsDevice() into InitPlatform() and ClosePlatform() for organization, consistency and coherence reasons.
Main reason for this change is that InitGraphicsDesign() was currently doing many other things:
* Initialize support library

* Setup window/framebuffer flags

* Initialize window/display

* Initialize graphic device

* Setup platfom callbacks (window, inputs...)

* Initialize inputs systems

* Initialize OpenGL extensions

* Initialize rlgl (buffers and shaders)

I thought it could be a good idea to unify all that into InitPlatform(), this way, not only all platform initialization is unified into a single function (using/updating required CORE data) but also allows to move InitWindow()/CloseWindow() back to rcore.c (still under consideration).
I tested PLATFORM_DESKTOP and it works ok, if you could give a try to the other platforms at some moment it would be great! Thanks!
PD. PLATFORM_ANDROID is a bit special so I kept the InitGraphicsDevice() but I reviewed it to do just that, init graphic device.
EDIT: Still considering dividing InitPlatform() into smaller functions or at least organize all the internal processes into sections with better comments.

I merged these changes into my fork with DRM input updates and it all is working.

@Bigfoot71 Compiled current master branch (2498170) on PLATFORM_DESKTOP, PLATFORM_WEB and PLATFORM_DRM and didn't get those warnings. I guess it's something with rcore_android.c in particular.

I just compiled using the Makefile for Android, and indeed, the warning did not appear. Only Android Studio warns me about it, but it still builds and runs without any issues afterward.
I'm not sure why this happens, rcore_android.c is properly included after the function declarations. Personally, I'm stumped on this matter.

@Bigfoot71 Does Android Studio keep some sort of cache that could be using some previous artifacts?

@ubkp Yes, Android Studio does it, but no matter how many times I invalidate the cache, clean the project, rebuild it entirely, the problem persists, and it's not just the IDE indicating it, but the compiler as well. It's strange but not very serious in my opinion.

on Android, I get these warnings for SetupFramebuffer(), SetupViewport(), InitTimer():

@Bigfoot71 yeah, I'm aware of those possible warning in some build systems, we can try to find a solution for them, for example declaring those functions also inside the platform modules... but those warning are probably more related to the build system than the compiler.

I merged these changes into my fork with DRM input updates and it all is working.

Really good to know! Feel free to send a PR with the new input system whenever you want!

but those warning are probably more related to the build system than the compiler.

I see, that would indeed be more consistent. Finally, I don't think it's necessary to duplicate the declarations solely for this issue, which seems rather 'isolated' and doesn't pose any problems for the final product. My opinion.

Following PR https://github.com/raysan5/raylib/pull/3420 by @ubkp, I also tried this on my end. Removing #include "rcore.h" seems to cause no issues when compiling raylib with its Makefile. However, it does cause these errors in Android Studio: log.txt
We might potentially find a macro definition that could help us determine whether to include this header or not. Alternatively, we could leave it by default, even if it's less consistent with the other headers.

A minor, somewhat peculiar thing to note is that the SetMousePosition() function is implemented on Android, which seems somewhat unnecessary unless there's a plan to implement a physical mouse on Android in the future.

I would also like to know if there are any measures to be taken on Android if InitGraphicsDevice() (or even InitPlatform()) fails. Should we let the activity run with a black screen, or should we take steps to close it? (or any other action)
Because we don't do anything with their returns, not even returning them to the user.

This is somewhat silly, but wouldn't it be better to add the void OpenURL(const char *url) from rcore_desktop.c to rcore_template.c? The template has code that seems to be for Android.

This is somewhat silly, but wouldn't it be better to add the void OpenURL(const char *url) from rcore_desktop.c to rcore_template.c?

@hbiblia The platform split is still in progress, there is a lot of things to review, if you find something that can be improved, please, send a PR.

A minor, somewhat peculiar thing to note is that the SetMousePosition() function is implemented on Android, which seems somewhat unnecessary unless there's a plan to implement a physical mouse on Android in the future.

Yeap, it's there because those are all functions exposed by raylib.h and should be in the library, despite doing nothing.

@michaelfiber @ubkp @Bigfoot71 Just added a new experimental platform: rcore_desktop_sdl.c. I implemented it in just a few hours and it works but not tested with all the examples and all the features. If anyone wants to help with it, you are welcome.

on Android, I get these warnings for SetupFramebuffer(), SetupViewport(), InitTimer():

@Bigfoot71 yeah, I'm aware of those possible warning in some build systems, we can try to find a solution for them, for example declaring those functions also inside the platform modules... but those warning are probably more related to the build system than the compiler.

I merged these changes into my fork with DRM input updates and it all is working.

Really good to know! Feel free to send a PR with the new input system whenever you want!

Yep, still testing but hopefully I'll have it ready soon. Gamepad support is looking good, mouse support is almost ready, then keyboard.

In other platforms it just finishes the program, not sure if possible to finish the application on Android...

We can always deallocate resources and use ANativeActivity_finish(). Without going into details, the application's lifecycle might not necessarily be finished, and the library would remain "loaded", but the native activity itself would indeed be terminated.
To completely finish the application unconditionally, you could use exit(-1), but this does not respect the application's lifecycle and is therefore not recommended, perhaps only in the case of a critical error, but in our case it is just a black screen.
So either we finish the native activity, even though it doesn't necessarily terminate the entire application, or we leave the screen black, even though we don't handle any returns. (which is still strange, but hey)

@raysan5 This was an awesome surprise. Fantastic job!
I'm still fighting a bit with SDL2 (2.28.4) not wanting to link statically to raylib (84818c9) here, but I've managed to successfully compile PLATFORM_DESKTOP_SDL dynamically on Linux (Ubuntu 22.04 64-bit, gcc 11.2.0).
Tested quite a few examples and most things appear to be working. Just had issues with the input system:

Mouse wheel getting stucked scrolling up or down;
Mouse sensitivity being really high;
Keypresses not working or working once;
Arrow keys causing segFaults.

However all these could be my fault from dynamically linking. I'll keep working on getting SDL2 to link statically here.

@raysan5 I managed to compile and run the example core_3d_camera_first_person.c on Linux Mint 21.2 64-bit (Ubuntu 22.04) using gcc 11.4.0. It runs successfully but doesn't recognize the keys and even produces a segmentation error when I use the arrow keys. The issue seems to originate from this section in PollInputEvents() - LINE 605:
// Keyboard events
case SDL_KEYDOWN:
{
    CORE.Input.Keyboard.currentKeyState[event.key.keysym.sym] = 1;

    if (event.key.keysym.sym == SDLK_ESCAPE)
    {
        CORE.Window.shouldClose = true;
    }
} break;

This problem arises because the key values in SDL do not match those in Raylib. Here's what I obtained for the up arrow key: WARNING: SDLK_UP=1073741906 - KEY_UP=265.
It seems that a complete key mapping is needed to resolve this issue.

Otherwise, I feel a bit foolish. The errors related to Android Studio were due to the presence of rcore_android.c in my CMakeLists.txt sources. The issues with undeclared functions and also errors when removing the inclusion of rcore.h in rcore_android.c are no longer present.
Please accept my apologies for my oversight.
@ubkp You can therefore remove the inclusion of rcore.h from rcore_android.c if you wish. If you have any other changes to make, don't hesitate. I'll read the commits and update the sources on my end if necessary.

@Bigfoot71 Do you want to fix the keypress issue on SDL? If yes, then I'll skip it and continue testing other functions.

@ubkp thank you very much for the reviews!!!
@Bigfoot71 I just did a quick test for the inputs, it requires some rework, probably some mapping from raylib defines to SDL keycodes.

Using scancodes is fine for you?

No, it should use keycodes, that's what the system maps internally for different keyboards.

Edit: Furthermore, raylib with GLFW also seems to use scancodes (when I press the Z key on my keyboard, it registers as KEY_W). So, why would you want to use keycodes with SDL?

@Bigfoot71 I could be wrong, but I think that's exactly the problem of scancodes.

Lets say I have a IsKeyPressed(KEY_Q) Quit(); somewhere on the program.
With keycodes only the key labelled as Q will trigger that, regardless of its physical position on the keyboard layout.
With scancodes that Q will be on the Q physical position of QWERTY and on the A physical position of AZERTY, which IMHO becomes a problem, once you start exposing rebinding to the user/interface.
So, unless I'm getting this wrong, I believe keycodes provide the desired operation. Isn't this the case?

@Bigfoot71 I could be wrong, but I think that's exactly the problem of scancodes.

@ubkp Yes, and precisely, I don't see this as a problem.
Currently, raylib with GLFW operates this way, and it's a good thing because the developer can code their game as if it were intended for a QWERTY keyboard (for example, using WASD for movement), and they won't have to do anything to support AZERTY keyboards (and, consequently, ZQSD for movement).
In summary, this is beneficial for gameplay and simplifies the developer's life.
However, indeed, if the developer expects the player to explicitly press the letter "Q", they'll need to press letter "A".
But this "issue" is already present in raylib with GLFW, so at least we maintain the same behavior between SDL and GLFW.
I don't see a problem with using keycodes and thus requiring the developer to set up a different configuration for each keyboard in their code. However, in my opinion, this should also be made consistent with raylib's GLFW version.

@raysan5 I can assure you 200% that when I press "A" on my AZERTY keyboard, KEY_Q is "true" on PLATFORM_DESKTOP.
However, I do acknowledge that from experience, this is not the case on PLATFORM_WEB, where my letter "A" will indeed be KEY_A.

The problem might not come from GLFW itself or its usage?

I'll take X11 as an example since I'm on Linux.
To obtain keys from scancodes, GLFW uses the static int translateKey(int scancode) function.
This function uses the _glfw.x11.keycodes array, which is created in the static void createKeyTables(void) function. In this function, I see the following:
{ GLFW_KEY_Q, "AD01" },

I've verified that this is correct for an American keyboard according to /usr/share/X11/xkb/symbols/us. But according to my keyboard layout in /usr/share/X11/xkb/symbols/fr, the code AD01 corresponds to "A":
key <AD01> { [     a,              A                                       ] };

So when I press "A," GLFW gets AD01, which it interprets as GLFW_KEY_Q.
This is obtained in processEvent(XEvent *event), which is called by _glfwPollEventsX11(void), and it's sent as an int key later in our function static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) in rcore_desktop.c.

Am I mistaken somewhere, or does this seem to be the issue?

@Bigfoot71 @raysan5
So, the main issue with scancodes is that the developer has to figure out the keyboard layout to display (e.g.: on the interface) the correct key label.
And with keycodes non-QWERTY keyboards get keys "scrambled" accordingly to it's layout, so it depends on the developer implementing some kind of rebind interface so they user can have some input coherence.
Both appear to have some big downsides. But scancodes looks like more forgiving, since, at least, it apparently won't break coherence for non-QWERTY, even tho the labels may not match there.

So, the main issue with scancodes is that the developer has to figure out the keyboard layout to display (e.g.: on the interface) the correct key label.

@ubkp I think so. As per my understanding, scancodes are the raw keyboard values generated by a key-press on the keyboard, independently of the label of the key. It's up to the system OS to map correctly those scancodes to the equivalent keycodes (labeled), following some kind of "standard" criteria.

And with keycodes non-QWERTY keyboards get keys "scrambled" accordingly to it's layout, so it depends on the developer implementing some kind of rebind interface so they user can have some input coherence.

It seems GLFW does internally that keycode mapping to standard US keyboard to provide the keyboard keys definition of the following list. If the mapping was done to another keyboard type (i.e. AZERTY) the same issue will happen with the defines.
More info:

ref GLFW doesn't care what layout you are using, if you look at the documentation, the physical keys are named after what they would be with a US layout. So that is the intended behavior.

So, if I'm right on my reasoning, one solution would be ignore GLFW defines and do the mapping from scancodes to keycodes manually in raylib BUT, my question is, how do we know the correct scancode to keycode mapping we should use? Are scancodes universal to all keyboards? How do we know if a keyboard is QWERTY or other?
Sorry, I'm a bit lost will all this issue at the moment...
@Bigfoot71 I think you can send the scancode implementation and we can test how it works with other keyboards/platforms. If everything works as expected, then we keep it; if not, we consider the other option.

@raysan5 The scancode mapping for SDL should work exactly the same as GLFW does currently on PLATFORM_DESKTOP. I'll keep the other version for keycodes in reserve just in case. I'll submit the pull request within the hour.

@Bigfoot71 Merged! Thanks for the improvement! I think with this addition and @ubkp function review, most of the functionality should be already in place!

Splitting InitWindow()/CloseWindow() is an excellent idea!
Update: there's just a few functions missing:
ToggleFullscreen
ToggleBorderlessWindowed
SetWindowState
ClearWindowState
SetWindowIcons
SetWindowMonitor
SetWindowFocused
GetWindowHandle
GetMonitorPhysicalWidth
GetMonitorPhysicalHeight
SetClipboardText
GetClipboardText
SetGamepadMappings
SetMouseCursor

I'll try to finish that overnight. I could fall short of a few that involve a bit more to port tho. But, on those, I'll try to at least add a basic implementation, so it can be reviewed later with more time.

Splitting InitWindow()/CloseWindow() is an excellent idea!

Done! It seems everything still works as expected!
@ubkp Thank you very much for listing the missing functions and working on them! I'm sure SDL could cover most of them!
With those implemented, the rcore_desktop_sdl.c platform will be mostly complete! After merging it I'm considering moving the platform implementation to a platform directory for better organization.

@ubkp @Bigfoot71 I could be confused and I should review this more carefully but afaik, at this moment raylib processes keycodes already mapped by GLFW, instead of scancodes. Afaik, PLATFORM_DRM also consumes keycodes, mapped by the OS to evdev. In any case, raylib behaviour with SDL should be the same than with GLFW.
I could be wrong on my assumption, this info needs to be verified.
The point is, if a message on the screen says "Press Q to quit", in an ideal scenario it should work on all keyboards (maybe current implementation does not).

In DRM there's a hard coded map in raylib mapping the scan codes to key codes. I've been looking into the most straight forward way to read the map file for the system and use that instead because then it'll match what the user sets.

Guys, did as many as I could overnight (#3436). Updated the table at https://github.com/raysan5/raylib/issues/3313#issuecomment-1767250636.
Already started work on ToggleFullscreen, ToggleBorderlessWindowed, SetWindowMonitor and GetMonitorPosition since they share a lot of logic. I should be able to deliver them during the day.
If anyone wants to take SetWindowState, ClearWindowState, SetWindowIcons, please, feel free to do so.

@ubkp I started SetWindowState, ClearWindowState, SetWindowIcons, it seems that I already only have SetWindowIcons to do and then tested all that.

There is a problem with DisableCursor(), the function hides the cursor for me but it is not brought back to the center of the window, which means that it is stuck at its edges.
I know I had this problem a long time ago and fixed it but I no longer have the slightest idea how...

There is a problem with DisableCursor(), the function hides the cursor for me but it is not brought back to the center of the window, which means that it is stuck at its edges. (SDL 2.0.20)
I know I had this problem a long time ago and fixed it but I no longer have the slightest idea how...

@Bigfoot71 Yeah, it appears the GLFW and SDL diverge a bit on what they consider "locking the cursor".
When I went through DisableCursor initially I was having a hard time finding an equivalent on SDL, the GLFW_CURSOR_DISABLED name threw me off (L985). But checking the GLFW documentation it said "GLFW_CURSOR_DISABLED hides and grabs the cursor, providing virtual and unlimited cursor movement. This is useful for implementing for example 3D camera controls."
The closest to that I could find was SDL_SetRelativeMouseMode which the SDL documentation mentions "While the mouse is in relative mode, the cursor is hidden, the mouse position is constrained to the window, and SDL will report continuous relative mouse motion even if the mouse is at the edge of the window."
But when I tested here (printing the cursor position, see example below), SDL_SetRelativeMouseMode still allowed the cursor to move freely (just hidden and limited to inside the window), so a single call like rcore_desktop.c (L988) didn't appear to work for SDL. I think that to keep the cursor trully centered it would have to be recentered at each frame or perhaps we have to normalize it's value (which is weird SDL_SetRelativeMouseMode doesn't already do).
#include "raylib.h"
#include <stdio.h>

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

        if (IsKeyDown(KEY_ONE))   { ShowCursor(); }
        if (IsKeyDown(KEY_TWO))   { HideCursor(); }
        if (IsKeyDown(KEY_THREE)) { EnableCursor(); }
        if (IsKeyDown(KEY_FOUR))  { DisableCursor(); }

        printf("%f %f \n", GetMousePosition().x, GetMousePosition().y);

        BeginDrawing();
        ClearBackground(RAYWHITE);
        DrawText("Test", 20, 20, 20, BLACK);
        DrawRectangle(20, 60, 40, 40, RED);
        EndDrawing();
    }
    CloseWindow();
    return 0;
}

@Bigfoot71 Would you like to handle this issue?

@ubkp Yes, no problem I can take care of it, I should be able to find an old project where I was able to manage this issue.

@ubkp Regarding the issue with DisableCursors(), it appears that there are two solutions.
First solution
The best solution would be to use SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "1"); just after calling SDL_SetRelativeMouseMode(SDL_TRUE);, but it seems that my version of SDL (2.0.20) does not support it...
SDL 2.0.20 was released in January 2022 if I believe this link, and the feature SDL_HINT_MOUSE_RELATIVE_WARP_MOTION was added in August 2022 if I believe this other link.
Second solution
The other, slightly more cumbersome solution would be to call this function for each frame (when the cursor is disabled):
SDL_WarpMouseInWindow(platform.window, CORE.Window.display.width / 2, CORE.Window.display.height / 2);

Which will reposition the cursor to the center of the screen.

@Bigfoot71 Tested SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "1"); and it also didn't work for me on SDL 2.28.4.
But, after taking a closer look at the SDL_MouseMotionEvent (doc) I think we're polling the wrong field for that. For that relative mouse move instead of:
CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;

We should be using:
CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;

Which does indeed appear to work as expected on a quick test I did here.
So, I think we could just add a cursorRelative parameter to the PlatformData struct and use that to poll the correct field during the PollInputEvents. Something like:
if (cursorRelative)
{
    CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
    CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
}
else
{
    CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
    CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
}

@Bigfoot71 What do you think? If you agree, could you add that change to #3439?

@Bigfoot71 I'm sorry, I missclicked and deleted the message.

@ubkp I saw it! Yes, event.motion.xrel and event.motion.yrel correspond to the delta, but that would indeed be quite clever! I think it would be a viable solution.

@Bigfoot71 Awesome! Thank you very much! My apologies again for deleting the message. I was trying to do two things at once and messed up.

Or we think that the problem comes from our way of obtaining the mouse delta. We could make sure that event.motion.xrel and event.motion.yrel are returned only when the mouse is moving.

Edit 2: I spoke too quickly, it doesn't work and it's quite logical in the end :/

@Bigfoot71 Yeah, you're right. Also good idea using the core_3d_camera_first_person.

Or we think that the problem comes from our way of obtaining the mouse delta. We could make sure that event.motion.xrel and event.motion.yrel are returned only when the mouse is moving.
Edit: This way the delta would always be correct and the mouse would not be stuck in the center of the screen when hidden. Because currently we calculate it ourselves with the position that we obtain ourselves, that's what poses the problem.

This sounds like a good solution.
By the way, I was messing around testing zeroing the CORE.Input.Mouse.previousPosition (L615), which improved it, but caused drifting.

@Bigfoot71 Could you please test this:
diff --git a/rcore_desktop_sdl.c b/rcore_desktop_sdl_FIXED.c
index cddee74..8657094 100644
--- a/rcore_desktop_sdl.c
+++ b/rcore_desktop_sdl_FIXED.c
@@ -63,6 +63,7 @@ typedef struct {

     SDL_Joystick *gamepad;
     SDL_Cursor *cursor;
+    bool cursorRelative;
 } PlatformData;

 //----------------------------------------------------------------------------------
@@ -529,7 +530,7 @@ void EnableCursor(void)
 {
     SDL_SetRelativeMouseMode(SDL_FALSE);
     SDL_ShowCursor(SDL_ENABLE);
-
+    platform.cursorRelative = false;
     CORE.Input.Mouse.cursorHidden = false;
 }

@@ -537,7 +538,7 @@ void EnableCursor(void)
 void DisableCursor(void)
 {
     SDL_SetRelativeMouseMode(SDL_TRUE);
-
+    platform.cursorRelative = true;
     CORE.Input.Mouse.cursorHidden = true;
 }

@@ -612,7 +613,8 @@ void PollInputEvents(void)
     CORE.Input.Mouse.currentWheelMove.y = 0;

     // Register previous mouse position
-    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+    if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
+    else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;

     // Reset last gamepad button/axis registered state
     CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
@@ -710,8 +712,17 @@ void PollInputEvents(void)
             } break;
             case SDL_MOUSEMOTION:
             {
-                CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
-                CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
+                if (platform.cursorRelative)
+                {
+                    CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
+                    CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
+                    CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
+                }
+                else
+                {
+                    CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
+                    CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
+                }
             } break;

             // Check gamepad events

What do you think? If you agree, feel free to add it to https://github.com/raysan5/raylib/pull/3439.

@ubkp I try this right after!
Otherwise, do you think it is necessary to check SDL_WasInit() in certain functions linked to the screen and the monitor? I probably would have done it but I see that the GLFW version does not check if the window has been initialized.

Otherwise, do you think it is necessary to check SDL_WasInit() in certain functions related to the screen and the monitor? I probably would have done it but I see that the GLFW version does not check if the window has been initialized.

@Bigfoot71 IMHO, I don't think it's necessary right now.

@ubkp Your solution for the delta works! I'm adding it to the PR!
The only issue left is with IsKeyPressed, which always returns true when a key is pressed, just like IsKeyDown
https://github.com/raysan5/raylib/assets/90587919/d38f4a49-d664-476b-867d-e8d8b6c51e3b

The only issue left is with IsKeyPressed, which always returns true when a key is pressed, just like IsKeyDown

@Bigfoot71 Oh yeah, forgot about that. Let me take a look at it.

@Bigfoot71 I think I found the problem.
Looks like we are polling by event.type (L656) exclusively. But SDL_PRESSED and SDL_RELEASED are provided by event.state on the SDL_KeyboardEvent (doc).
I guess the solution could be checking if (state.state == SDL_PRESSED) inside case SDL_KEYDOWN: (L679). And checking  if (state.state == SDL_RELEASED) inside case SDL_KEYUP: (L691).
What do you think?

@ubkp, look no further, I've found it, and it was quite simple. I had realized that it wasn't working for all the keys, and I immediately guessed that it was the loop for defining the previous keys.
Currently, we are doing this:
    for (int i = 0; i < 260; i++)
    {
        CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
        CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
    }

However, with MAX_KEYBOARD_KEYS set to 512, I did this, and it seems to work perfectly:
    for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
    {
        CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
        CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
    }

@Bigfoot71 Great catch! Tested here and that's indeed the fix. Great job!

@ubkp It was the sneaky error; now we need to see what's missing. I think we've covered almost everything, haven't we? (Except for SetWindowMonitor)

@Bigfoot71 Yup, I think this was indeed mostly it. It was a great sprint! Really fantastic job! :+1:
There are a few minor things like ToggleFullscreen setting vsync on rcore_desktop.c (L194-L196) (that I don't know if we should add too? @raysan5). And I'm sure more issues will popup as we use it more, but the basic core operation should be there.
@raysan5 After reviewing and merging #3439, if you want to move everything to a platform directory, as you mentioned, we can probably continue polishing after that.

@ubkp I just see that only GetWindowScaleDPI and SetWindowIcons are missing (not to be confused with SetWindowIcon).
For DPI, it doesn't seem to work the same way as with GLFW. Here is the SDL function (doc):
int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);

It returns a diagonal, horizontal, and vertical value, but I'm not sure if you need to divide the value or use it as is. (to see)
I will now see for SetWIndowIcons()

I just see that only GetWindowScaleDPI and SetWindowIcons are missing (not to be confused with SetWindowIcon).

@Bigfoot71 That's true. I actually thought SetWindowIcons was SetWindowIcon. TBQH, now that you mentioned it, I don't even see how SetWindowIcons is supposed to be used.

It returns a diagonal, horizontal, and vertical value, but I'm not sure if you need to divide the value or use it as is. (to see)

For GetWindowScaleDPI I believe we need the hdpi and vdpi. And as I type this I just realized I probably used the wrong dpi on GetMonitorPhysicalWidth and GetMonitorPhysicalHeight. I should have used ddpi instead of vdpi. I'll do a quick test here to confirm it.

@Bigfoot71 @ubkp thank you very for all the latests reviews and improvements!
Excuse for the late answer, for the last two days, I've been working on Switch platform... and thanks to the platform split, it worked very nice! Unfortunately, that platform can not be open sourced...

@michaelfiber @ubkp @Bigfoot71 Hi! Just moved the platforms rcore(s) to a separate directory for better organization. Please let me know if any compilation issue arises because of that.
Also marked InitPlatform() and ClosePlatform() as external (despite technically being in the same module). It shouldn't be a problem; some "special" platforms could require those functions to be external... ;)

Tested current master branch (081fffd) successfully on PLATFORM_DESKTOP, PLATFORM_DESKTOP_SDL, PLATFORM_WEB and PLATFORM_DRM.
Environment: Linux (Ubuntu 22.04 64-bit); Web (Firefox 115.3.1esr 64-bit and Chromium 117.0.5938.149 64-bit); DRM (Raspberry Pi 3 Model B 1.2 with Raspberry Pi OS 11 Bullseye 32-bit armhf).

No problems reported with the Makefile for PLATFORM_ANDROID (NDK 25.2.9519653)
Nor any problems reported with Android Studio.

I think this issue can already by closed.
@ubkp @michaelfiber @Bigfoot71 thank you very much for making it possible! ♥
I think is about time to prepare raylib 5.0 release.   Trying to close some additional issues and squiz some extra features...

@raysan5 Just one last issue. While using rcore_desktop_sdl.c, after resizing the window (be it by dragging the borders, or with SetWindowSize), the window will be resized, but the rendered area won't follow and will stay on the bottom left of the window.
Screenshot

Code example
#include "raylib.h"

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

    SetWindowState(FLAG_WINDOW_RESIZABLE);

    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(RAYWHITE);
            DrawRectangleLinesEx((Rectangle){ 0, 0, 800, 450 }, 2.0f, RED);
            DrawText(TextFormat("Window size: %i %i", GetScreenWidth(), GetScreenHeight()), 20, 20, 20, BLACK);
        EndDrawing();
    }
    CloseWindow();
    return 0;
}

If you can, could you please take a look at this issue. I really wasn't able to figure out why. It's probably something that should be fixed before the 5.0 release.

@raysan5 I think the issue above is because we're missing something like WindowSizeCallback on rcore_desktop_sdl.c (L1553-L1584) that will update the CORE.Window.currentFbo.width/height (L1558-L1559) when there's a resize event.
We probably need to poll the SDL_WINDOWEVENT_SIZE_CHANGED (doc) to update the CORE.Window.currentFbo.width/height similar to PollInputEvents. It could be added to PollInputEvents, but since it's not an input event, it could cause some confusion.

Maybe an event watch could help us avoid putting the resizing detection in the input-related function. https://wiki.libsdl.org/SDL2/SDL_AddEventWatch
I could take a look at it tomorrow if I have some time, if you'd like.

@Bigfoot71 Very good find! SDL_AddEventWatch is probably the best/correct solution.
By the way, while inspecting the PollInputEvents with attention, I found that we already do that inside it (L993-L1004).
So, as a temporary/stopgap fix, changed it to this (which fixes the issue):
switch (event.window.event)
{
    case SDL_WINDOWEVENT_RESIZED:
    case SDL_WINDOWEVENT_SIZE_CHANGED:
    {
        int width = event.window.data1;
        int height = event.window.data2;
        SetupViewport(width, height);
        CORE.Window.screen.width = width;
        CORE.Window.screen.height = height;
        CORE.Window.currentFbo.width = width;
        CORE.Window.currentFbo.height = height;
        CORE.Window.resizedLastFrame = true;
    } break;
    case SDL_WINDOWEVENT_LEAVE:
    case SDL_WINDOWEVENT_HIDDEN:
    case SDL_WINDOWEVENT_MINIMIZED:
    case SDL_WINDOWEVENT_FOCUS_LOST:
    case SDL_WINDOWEVENT_ENTER:
    case SDL_WINDOWEVENT_SHOWN:
    case SDL_WINDOWEVENT_FOCUS_GAINED:
    case SDL_WINDOWEVENT_MAXIMIZED:
    case SDL_WINDOWEVENT_RESTORED:
    default: break;
}

@Bigfoot71 Since I have this ready, I'll add it to #3450. But feel free to revert it and properly fix it with SDL_AddEventWatch if you want. :+1:

@ubkp Yeah, I prefer to avoid the callback system and just do the polling manually, I just left the event.window.event switch ready to use for this situations, actually the other event should be probably also processed accordingly and mapped to raylib window flags.


[PINOT-4768] Handle exceptions when a table gets dropped while committing an LLC segment

We handle all exceptions inside the segment completion manager, and return a failed response.
Added unit test

Codecov Report

:exclamation: No coverage uploaded for pull request base (master@066315a). Click here to learn what that means.
The diff coverage is 79.48%.

@@            Coverage Diff            @@
##             master    #1275   +/-   ##
=========================================
  Coverage          ?   67.32%
=========================================
  Files             ?      774
  Lines             ?    37745
  Branches          ?     4933
=========================================
  Hits              ?    25413
  Misses            ?    10652
  Partials          ?     1680

Impacted Files
Coverage Δ

.../core/realtime/PinotLLCRealtimeSegmentManager.java
77.73% <100%> (ø)

.../helix/core/realtime/SegmentCompletionManager.java
68.31% <78.37%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 066315a...3663eea. Read the comment docs.


make emergency lights (de)constructable

add an emergency light node to the LightFixture construction graph
add a recipe entry to the construction menu for emergency light
make emergency light entity at the emergency light node on the graph

About the PR

I made emergency lights constructible and deconstructible.
Why / Balance

When I was playing the game, I right clicked an emergency light and there was an option to "Begin Deconstructing". which I clicked, and then I examined the emergency light and it said to use a screwdriver next. But when I went to do that, nothing happened. It turns out this examine shows up I think because the parent of the emergency light entity has it at the light tube point on the light fixture construction graph by default. So, being annoyed, I went and looked up how to code for ss14 to fix this. The recipe is one steel and one glass, and I figure since the emergency light looks almost exactly like the empty light fixture, just adding glass to the recipe would be fine. It's a pretty simple (and very small) looking structure with not much use so I think it would be overkill to require using a lathe to print an emergency light like with the other wall lights like bulbs and tubes.
Technical details

I fixed it by adding a new node on the light fixture graph for emergency lights. This only required changing the yamls to:

add a construction node for emergency lights in light fixture graph
add the recipe to the construction menu
emergency light entity construction component set to this new node

Requirements

[x ] I have read and am following the Pull Request and Changelog Guidelines.
[x ] I have added media to this PR or it does not require an ingame showcase.

Changelog

:cl:

add: Emergency lights can be constructed and deconstructed

The test fail is real.
EmergencyLight inherits this from AlwaysPoweredWallLight, meaning if you destroy it by force, you will get 2 steel sheets, while constructing it only needs 1.

The test fail is real. EmergencyLight inherits this from AlwaysPoweredWallLight, meaning if you destroy it by force, you will get 2 steel sheets, while constructing it only needs 1.

Hi, thanks for the explanation, I am impressed by this testing, this is my first time trying to do coding , I updated the PR so that the emergency light is destroyed into 1 steel and 1 glass shard

mmmm... it says they have an internal battery, maybe they should need a battery?

mmmm... it says they have an internal battery, maybe they should need a battery?

All the other lights are really cheap to build as well, so I think it's fine without for consistency reasons.

if anything it should be a capacitor not battery, that would be really annoying

@slarticodefast is it still awaiting changes ?

Thank you for your first contribution!
The code looks good and it all tested fine in-game


[now-cli] Display warning when changing the secret name

Display a warning when changing the secret name on now secrets add.

Fixes https://github.com/zeit/now/issues/2969

Codecov Report

Merging #2975 into canary will decrease coverage by <.01%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           canary    #2975      +/-   ##
==========================================
- Coverage   13.36%   13.35%   -0.01%
==========================================
  Files         267      267
  Lines       10333    10338       +5
  Branches     1215     1217       +2
==========================================
  Hits         1381     1381
- Misses       8890     8895       +5
  Partials       62       62

Impacted Files
Coverage Δ

src/util/dev/server.ts
66.95% <0%> (-0.12%)
:arrow_down:

src/util/alias/get-deployment-for-alias.ts
0% <0%> (ø)
:arrow_up:

src/commands/secrets.js
0% <0%> (ø)
:arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ecdde7c...941931f. Read the comment docs.


Wrong linting suggestion for "ring" styles

Reporting an odd linting suggestion:
"Replace blue-light·ring-2 with 2·ring-blue-light"

Thanks @bradlc
I see what you mean (when factoring in the not-shown text it makes sense)
This leads to a related question:
The style at current is stated as:
@apply ring-blue-light ring-2;
Then I get this warning:
WARN  12:58:15 [vite] warning:                                                                                49:15  warning  Replace `blue-light·ring-2` with `2·ring-blue-light`  prettier/prettier

✖ 1 problem (0 errors, 1 warning)
  0 errors and 1 warning potentially fixable with the `--fix` option.

  Plugin: vite:eslint
  File: /Users/gareth/dev/benchmark-urbanism/interface/src/components/headless/SwitchWrapper.vue

For some reason this doesn't fix automatically when linting on save, so when I manually change the entry to:
@apply ring-2 ring-blue-light;
Then it reverts to the prior order on save.
So, it seems like there is some sort of lint clash going on, maybe between prettier and style lint?
My style lint is set to:
module.exports = {
  extends: [
    'stylelint-config-recommended-vue',
    'stylelint-config-standard',
    'stylelint-config-prettier',
  ],
  rules: {
    'selector-nested-pattern': '^&',
  },
}


Add section version to README

Version

vagrant-hashistack
consul
nomad
vault
consul-template

0.4.3
1.8.4
0.12.4
1.5.3
0.25.1

0.4.0
1.8.3
0.12.3
1.5.2
0.25.1

Might need to expand columns. Also, having such a table either at the beginning or end of the documentation

I guess it should also be a part of release notes?

Only last version in README.md?


upgrade the latest version of the vtab library

This makes use of the new EarlyOrderByConstraintExit option, which is an opt-in optimization that allows the vtab library to determine when an "early exit" is feasible in some queries. This is useful for avoiding full table scans on slower API tables (like GitHub stargazers for instance).

Codecov Report

Merging #176 (b18570e) into main (7f7e5ea) will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##             main     #176   +/-   ##
=======================================
  Coverage   68.30%   68.30%
=======================================
  Files          41       41
  Lines        1991     1991
=======================================
  Hits         1360     1360
  Misses        409      409
  Partials      222      222

Impacted Files
Coverage Δ

extensions/internal/git/native/blame.go
67.70% <ø> (ø)

extensions/internal/git/native/files.go
66.32% <ø> (ø)

extensions/internal/git/native/stats.go
64.80% <ø> (ø)

extensions/internal/github/org_repos.go
75.32% <ø> (ø)

extensions/internal/github/repo_issues.go
73.42% <ø> (ø)

extensions/internal/github/repo_prs.go
76.83% <ø> (ø)

extensions/internal/github/stargazers.go
74.52% <ø> (ø)

extensions/internal/github/starred_repos.go
69.38% <ø> (ø)

extensions/internal/github/user_repos.go
72.72% <ø> (ø)

...ensions/internal/sourcegraph/sourcegraph_search.go
51.21% <ø> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7f7e5ea...b18570e. Read the comment docs.


feedback

I have put comments into the commits, this is just an issue to link to them

A minor changes has been made at HanzCEO@ce068f321eaae26ca32593707c867f05bdb00cb2 on develop branch


Linkify welcome issue to open options page

Fixes https://github.com/refined-github/refined-github/issues/5080

Demo
https://user-images.githubusercontent.com/1402241/145529215-3f880d8e-ac13-4901-94db-e0b40ce36866.mov
Test URL
https://github.com/refined-github/refined-github/issues/3543

Also cleans it up a bit


feat(paeckchen-cli): add source-map option

relates to #51

Coverage remained the same at 100.0% when pulling c93af352ef1bfc9817424bd9e3c877ddfaeaea4a on cli/source-maps into 866f2d9702a9787beca879acd52b9629ee510a48 on master.


About using both Fusion and Stack

Hello, I try to implement a cross-lingual transfer model. What I want is:

the output of  2 language adapters lan_a and lan_b be fused and then input to a classification adapter.
all of the 2 language adapters and classdification task adapter can be trained

I don't know which one I need to use,  train_adapter_fusion or train_adapter,and how to use.
Here is my codes:
lang_adapter_config = AdapterConfig.load("pfeiffer", reduction_factor=8)
model.load_adapter("en", config=lang_adapter_config, model_name = 'xlm-roberta-base')
model.load_adapter("de", config=lang_adapter_config, model_name = 'xlm-roberta-base')

model.add_adapter_fusion(["en", "de"])
model.add_adapter("task")
model.add_classification_head("task", num_labels=2)

model.active_adapters = Stack(Fuse("en", "de"), "task")
model.train_adapter_fusion(Stack(Fuse("en","de"), "task"))

Hi @calpt, sorry I have been bothering you in recent time.
I am also trying to do a similar thing: I was to fuse 2 adapters and then stack the fused adapters on the task adapter. During training, I just want to train the fusion layer, the task adapter, and the task head.
Below is my code snippet:
from transformers import AutoAdapterModel
from transformers import AdapterConfig
from transformers.adapters.composition import Fuse, Stack

# Load model
model = AutoAdapterModel.from_pretrained("xlm-roberta-base")
model.load_adapter("en/wiki@ukp", with_head=False)
model.load_adapter("de/wiki@ukp", with_head=False)

fusion_adapters = ['en','de']
model.add_adapter_fusion(fusion_adapters)
model.add_adapter("task")
model.add_classification_head("task", num_labels=4)
model.train_adapter_fusion(Stack(Fuse("en","de"), "task"))

However, the above snippet only trains the fusion and the task head without the task adapter. In addition, I tried the following:
model.apply_to_adapter_layers(lambda i, layer: layer.enable_adapters(Stack(Fuse("en","de"), "task"), True, True))

Does adapter-transformer support what I am trying to do? What would suggest I do? Unfreeze the task adapters separately.

Any leads on this? Were you able to do it? I am stuck on the same issue.

@ajesujoba @ahtamjan @calpt, this could be a potential solution that works for me and for now:
for name, module in model.named_modules():
    for name_, param_ in module.named_parameters():
        param_.requires_grad = "task" in name or "adapter_fusion_layer" in name
            model.set_active_adapters(Stack(Fuse("en","de"), "task"))

model.set_active_adapters(Stack(Fuse("en","de"), "task"))

This only trains the fusion layer, task adapter, and classification head.


Added script to download the crawl

This PR is in reference to #1
@justinccdev  , as you suggested, I added a separate script for dumping and I am attaching a sample output of the dump. Please let me know if it has got issues.
crawl.txt

Hey @justinccdev ,
I incorporated the changes. Please have a look.
Yes, I have been using Sublime till now. I shifted to pycharm and it is really helpful while working on a large code base .
Thanks for the suggestions :)

Thanks @innovationchef


Remove TomSelect.define from plugins

This moves the TomSelect.define call out of the plugins and into the tom-select.popular.js and tom-select.complete.js. This allows plugins to be imported individually using Webpack (or other build tools).
import TomSelect from "tom-select/dist/js/tom-select.base";
TomSelect.define("remove_button", require("tom-select/dist/js/plugins/remove_button"));
TomSelect.define("clear_button", require("tom-select/dist/js/plugins/clear_button"));

This could be a breaking change if someone is importing plugins directly and expecting it to call TomSelect.define. They now need to call that themselves when importing plugins (as shown here). I doubt that is a common use case but probably worth mentioning in the change log.
Also see #222 and #68.

Looks good, thanks!


Wizard Modal

Hello @shadcn !
Thanks for creating this repo. It is really helpful. Could you add a Wizard Modal example?
Best!

+1

+1

+1


Set queue options

Hi,
i was wondering if there is a way to set queue durability separately from exchange durability?
When i set the exchange as durable and of 'fanout' type the queue inherits this options which is not intended behavior in my app.
EDIT:
now that i have checked, there is actually no possibility to set any of the queue options (passive, durable, exclusive, auto_delete).
Is there a plan to implement these options?

So far, there are no plans to make queue options configurable. This is mainly due to the fact, that I did not have a need for it. This is definitely something worth to be taken into consideration.

I have looked at the code and i could do this (implement all remaining queue options) in a few hours tomorrow morning without breaking BC, if you are open to pull requests?

Sure, PRs are welcome.

Hi, we are going to run it in production, to avoid php script pooling. thank you very much for your work. regards

It would be nice to get a new release since i already have automated builds that just download the binaries. I would prefer to keep it simple and without additional build steps. Thank you


documentation directory should be plural

Currently https://github.com/oracle/oracle-database-operator/tree/main/doc is singular, it should be plural naming docs

Addressed this
Thanks


MF-1154 - Move UUID provider to project root

Signed-off-by: Manuel Imperiale<EMAIL_ADDRESS>Resolves #1154

Codecov Report

Merging #1172 into master will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##           master    #1172   +/-   ##
=======================================
  Coverage   77.42%   77.42%
=======================================
  Files         102      102
  Lines        6856     6856
=======================================
  Hits         5308     5308
  Misses       1178     1178
  Partials      370      370

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a5fb55c...28f40d1. Read the comment docs.

@mainflux/maintainers Why not moving this to /pkg it's a great candidate as a shared package.

@nmarcetic I'm not against. I also wanted to know where do you think that we should put uuid mock. In pkg/uuid/mocks directory or in a specific pkg/mocks directory?

@nmarcetic I'm not against. I also wanted to know where do you think that we should put uuid mock. In pkg/uuid/mocks directory or in a specific pkg/mocks directory?

If those mocks are not sharable (e.g not used by there packages, but only by /pkg/uuid) then I would keep them under /pkg/uuid