diff --git a/Framework/App.cs b/Framework/App.cs
index 1dd4254..be9a34f 100644
--- a/Framework/App.cs
+++ b/Framework/App.cs
@@ -303,12 +303,14 @@ public static void Run(string applicationName, int width, int height, bool fulls
MainThreadID = Thread.CurrentThread.ManagedThreadId;
+ // toggle fulscreen flag
if (fullscreen)
flags |= Platform.FosterFlags.Fullscreen;
+ // run the application
+ var name = Platform.ToUTF8(applicationName);
title = applicationName;
Name = applicationName;
- var name = Platform.ToUTF8(applicationName);
Platform.FosterStartup(new()
{
@@ -327,6 +329,9 @@ public static void Run(string applicationName, int width, int height, bool fulls
UserPath = Platform.ParseUTF8(Platform.FosterGetUserPath());
Graphics.Initialize();
+ // load default input mappings if they exist
+ Input.AddDefaultSdlGamepadMappings(AppContext.BaseDirectory);
+
// Clear Time
Time.Frame = 0;
Time.Duration = new();
diff --git a/Framework/Input/Input.cs b/Framework/Input/Input.cs
index 33587cb..4e78f49 100644
--- a/Framework/Input/Input.cs
+++ b/Framework/Input/Input.cs
@@ -3,6 +3,7 @@
using System.Collections.ObjectModel;
using System.Numerics;
using System.Runtime.InteropServices;
+using System.Text;
namespace Foster.Framework;
@@ -51,30 +52,42 @@ public static class Input
///
public static float RepeatInterval = 0.03f;
+ ///
+ ///
+ ///
public delegate void TextInputHandler(char value);
+
+ ///
+ /// Called whenever keyboard text is typed
+ ///
public static event TextInputHandler? OnTextEvent;
- internal static readonly List> virtualButtons = new List>();
+ ///
+ /// Holds references to all Virtual Buttons so they can be updated.
+ ///
+ internal static readonly List> virtualButtons = [];
///
- /// Run at the beginning of a frame to step the input state.
- /// After this, the Application will poll the platform for more inputs, which call back
- /// to the various Input.On internal methods.
+ /// Loads 'gamecontrollerdb.txt' from a local file or falls back to the
+ /// default embedded SDL gamepad mappings
///
- internal static void Step()
+ internal static void AddDefaultSdlGamepadMappings(string relativePath)
{
- LastState.Copy(State);
- State.Copy(nextState);
- nextState.Step();
+ var path = Path.Combine(relativePath, "gamecontrollerdb.txt");
+ if (File.Exists(path))
+ AddSdlGamepadMappings(File.ReadAllLines(path));
+ }
- for (int i = virtualButtons.Count - 1; i >= 0; i--)
- {
- var button = virtualButtons[i];
- if (button.TryGetTarget(out var target))
- target.Update();
- else
- virtualButtons.RemoveAt(i);
- }
+ ///
+ /// Loads a list of SDL Gamepad Mappings.
+ /// You can find more information here: https://github.com/mdqinc/SDL_GameControllerDB
+ /// By default, any 'gamecontrollerdb.txt' found adjacent to the application at runtime
+ /// will be loaded automatically.
+ ///
+ public static void AddSdlGamepadMappings(string[] mappings)
+ {
+ foreach (var mapping in mappings)
+ Platform.SDL_GameControllerAddMapping(mapping);
}
///
@@ -94,6 +107,27 @@ public static string GetClipboardString()
return Platform.ParseUTF8(ptr);
}
+ ///
+ /// Run at the beginning of a frame to step the input state.
+ /// After this, the Application will poll the platform for more inputs, which call back
+ /// to the various Input.On internal methods.
+ ///
+ internal static void Step()
+ {
+ LastState.Copy(State);
+ State.Copy(nextState);
+ nextState.Step();
+
+ for (int i = virtualButtons.Count - 1; i >= 0; i--)
+ {
+ var button = virtualButtons[i];
+ if (button.TryGetTarget(out var target))
+ target.Update();
+ else
+ virtualButtons.RemoveAt(i);
+ }
+ }
+
private static unsafe void OnText(IntPtr cstr)
{
byte* ptr = (byte*)cstr;
diff --git a/Framework/Platform.cs b/Framework/Platform.cs
index d48f6f1..4611432 100644
--- a/Framework/Platform.cs
+++ b/Framework/Platform.cs
@@ -313,6 +313,11 @@ static unsafe Platform()
public static extern void FosterDraw(ref FosterDrawCommand command);
[DllImport(DLL)]
public static extern void FosterClear(ref FosterClearCommand command);
+
+ // Non-Foster Calls:
+
+ [DllImport(DLL, CharSet = CharSet.Ansi)]
+ public static extern int SDL_GameControllerAddMapping(string mappingString);
// [DllImport(DLL)]
// public static extern void emscripten_set_main_loop(IntPtr action, int fps, bool simulateInfiniteLoop);
diff --git a/Platform/libs/lib64/libFosterPlatform.so b/Platform/libs/lib64/libFosterPlatform.so
index e098793..1c0ca16 100755
Binary files a/Platform/libs/lib64/libFosterPlatform.so and b/Platform/libs/lib64/libFosterPlatform.so differ
diff --git a/Platform/src/foster_platform.c b/Platform/src/foster_platform.c
index 195aeb7..db2d732 100644
--- a/Platform/src/foster_platform.c
+++ b/Platform/src/foster_platform.c
@@ -86,7 +86,7 @@ void FosterStartup(FosterDesc desc)
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitorv2");
// use physical button layout, not labels
- SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
+ SDL_SetHintWithPriority(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0", SDL_HINT_OVERRIDE);
// by default allow controller presses while unfocused, let game decide if it should handle them
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");