forked from MeloNX/MeloNX
Add Controller Selector and Update MoltenVK
This commit is contained in:
parent
674824184a
commit
ab28f9a24a
@ -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;
|
||||||
|
Binary file not shown.
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -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
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user