Add Controller Selector and Update MoltenVK

This commit is contained in:
Stossy11 2024-11-25 06:31:38 +11:00
parent 674824184a
commit ab28f9a24a
10 changed files with 125 additions and 51 deletions

View File

@ -536,6 +536,10 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
@ -608,6 +612,10 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;

View File

@ -15,6 +15,8 @@ extern "C" {
// Declare the main_ryujinx_sdl function, matching the signature // Declare the main_ryujinx_sdl function, matching the signature
int main_ryujinx_sdl(int argc, char **argv); int main_ryujinx_sdl(int argc, char **argv);
const char* get_game_controllers();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -10,7 +10,7 @@ import SwiftUI
import SDL2 import SDL2
import GameController import GameController
struct Controller: Identifiable { struct Controller: Identifiable, Hashable {
let id: String let id: String
let name: String let name: String
} }
@ -133,24 +133,34 @@ class Ryujinx {
return args return args
} }
func getConnectedControllers() { func getConnectedControllers() -> [Controller] {
guard let jsonPtr = get_game_controllers() else {
// Retrieve all connected controllers return []
let controllers = GCController.controllers() }
for controller in controllers { // Convert the unmanaged memory (C string) to a Swift String
if let controllerID = controller.vendorName { let jsonString = String(cString: jsonPtr)
// Assuming controller's name is used as the ID
let controllerName = controller.vendorName ?? "Unknown Controller" var controllers: [Controller] = []
// You can customize the key format here // Splitting the string by newline
DispatchQueue.main.async { let lines = jsonString.components(separatedBy: "\n")
self.controllerMap.append(Controller(id: controllerID, name: controllerName))
// Parsing each line
for line in lines {
if line.contains(":") {
let parts = line.components(separatedBy: ":")
if parts.count == 2 {
let id = parts[0].trimmingCharacters(in: .whitespacesAndNewlines)
let name = parts[1].trimmingCharacters(in: .whitespacesAndNewlines)
controllers.append(Controller(id: id, name: name))
} }
} }
} }
return controllers
} }

View File

@ -18,7 +18,8 @@ struct ContentView: View {
@State public var theWindow: UIWindow? = nil @State public var theWindow: UIWindow? = nil
@State private var virtualController: GCVirtualController? @State private var virtualController: GCVirtualController?
@State var game: URL? = nil @State var game: URL? = nil
@State var controllerss: [Controller] = [] @State var controllersList: [Controller] = []
@State var currentControllers: [Controller] = []
@State private var settings: [MoltenVKSettings] = [ @State private var settings: [MoltenVKSettings] = [
MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0"), MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0"),
@ -56,40 +57,54 @@ struct ContentView: View {
} }
var body: some View { var body: some View {
NavigationStack {
if let game { if let game {
ZStack { ZStack {
SDLViewRepresentable { displayid in SDLViewRepresentable { displayid in
start(displayid: 0) start(displayid: 0)
}
Text("Loading...")
.onAppear {
// start(displayid: 0)
}
} }
Text("Loading...") } else {
.onAppear { HStack {
// start(displayid: 0) GameListView(startemu: $game)
} .onAppear() {
} Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in
} else { controllersList = Ryujinx().getConnectedControllers()
HStack { controllersList.removeAll(where: { $0.id == "0" })
GameListView(startemu: $game) }
.onAppear() { }
Ryujinx().getConnectedControllers()
} List {
Button {
List { controllersList = Ryujinx().getConnectedControllers()
ForEach($settings, id: \.self) { $setting in controllersList.removeAll(where: { $0.id == "0" })
HStack { } label: {
Text(setting.string) Text("Refresh")
.padding() }
TextField("Value", text: $setting.value) ForEach(controllersList, id: \.self) { controller in
.textFieldStyle(RoundedBorderTextFieldStyle())
.onChange(of: setting.value) { newValue in Button {
setenv(setting.string, newValue, 1) if currentControllers.contains(where: { $0.id == controller.id }) {
currentControllers.removeAll(where: { $0.id == controller.id })
} else {
currentControllers.append(controller)
} }
} label: {
Text(controller.name)
}
Spacer()
if currentControllers.contains(where: { $0.id == controller.id }) {
Image(systemName: "checkmark.circle.fill")
}
} }
} }
} }
} }
} }
} }
@ -104,7 +119,7 @@ struct ContentView: View {
debuglogs: false, debuglogs: false,
tracelogs: false, tracelogs: false,
listinputids: false, listinputids: false,
inputids: ["1-dc180005-045e-0000-130b-0000ff870001"], // "2-1fd70005-057e-0000-0920-0000ff870000"], inputids: currentControllers.map(\.id),// "1-dc180005-045e-0000-130b-0000ff870001"], // "2-1fd70005-057e-0000-0920-0000ff870000"],
ryufullscreen: true ryufullscreen: true
) )

View File

@ -39,6 +39,13 @@ using System.Threading;
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key; using Key = Ryujinx.Common.Configuration.Hid.Key;
using System.Linq;
public class GamepadInfo
{
public string Id { get; set; }
public string Name { get; set; }
}
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless.SDL2
{ {
@ -125,6 +132,38 @@ namespace Ryujinx.Headless.SDL2
.WithNotParsed(errors => errors.Output()); .WithNotParsed(errors => errors.Output());
} }
[UnmanagedCallersOnly(EntryPoint = "get_game_controllers")]
public static unsafe IntPtr GetGamepadList()
{
List<GamepadInfo> gamepads = new List<GamepadInfo>();
IGamepad gamepad;
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
// Collect gamepads from the keyboard driver
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
{
gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
gamepads.Add(new GamepadInfo { Id = id, Name = gamepad.Name });
gamepad.Dispose();
}
// Collect gamepads from the gamepad driver
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
{
gamepad = _inputManager.GamepadDriver.GetGamepad(id);
gamepads.Add(new GamepadInfo { Id = id, Name = gamepad.Name });
gamepad.Dispose();
}
// Serialize the gamepad list to a custom string format
string result = string.Join("\n", gamepads.Select(g => $"{g.Id}:{g.Name}")); // Ensure System.Linq is available
// Convert the string to unmanaged memory
IntPtr ptr = Marshal.StringToHGlobalAnsi(result);
return ptr;
}
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index) private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
{ {
if (inputId == null) if (inputId == null)

View File

@ -185,8 +185,8 @@ namespace Ryujinx.Headless.SDL2
FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
} }
WindowHandle = SDL_GetWindowFromID(1); // WindowHandle = SDL_GetWindowFromID(1);
// WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags()); WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags());
if (WindowHandle == IntPtr.Zero) if (WindowHandle == IntPtr.Zero)
{ {

View File

@ -96,12 +96,12 @@ namespace Ryujinx.SDL2.Common
SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE);
string gamepadDbPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt"); // string gamepadDbPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt");
if (File.Exists(gamepadDbPath)) // if (File.Exists(gamepadDbPath))
{ // {
SDL_GameControllerAddMappingsFromFile(gamepadDbPath); // SDL_GameControllerAddMappingsFromFile(gamepadDbPath);
} // }
_registeredWindowHandlers = new ConcurrentDictionary<uint, Action<SDL_Event>>(); _registeredWindowHandlers = new ConcurrentDictionary<uint, Action<SDL_Event>>();
_worker = new Thread(EventWorker); _worker = new Thread(EventWorker);