mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-02 23:37:10 +02:00
Miria: The Death of OpenTK 3 (#2194)
* openal: Update to OpenTK 4 * Ryujinx.Graphics.OpenGL: Update to OpenTK 4 * Entirely removed OpenTK 3, still wip * Use SPB for context creation and handling Still need to test on GLX and readd input support * Start implementing a new input system So far only gamepad are supported, no configuration possible via UI but detected via hotplug/removal Button mapping backend is implemented TODO: front end, configuration handling and configuration migration TODO: keyboard support * Enforce RGB only framebuffer on the GLWidget Fix possible transparent window * Implement UI gamepad frontend Also fix bad mapping of minus button and ensure gamepad config is updated in real time * Handle controller being disconnected and reconnected again * Revert "Enforce RGB only framebuffer on the GLWidget" This reverts commit 0949715d1a03ec793e35e37f7b610cbff2d63965. * Fix first color clear * Filter SDL2 events a bit * Start working on the keyboard detail - Rework configuration classes a bit to be more clean. - Integrate fully the keyboard configuration to the front end (TODO: assigner) - Start skeleton for the GTK3 keyboard driver * Add KeyboardStateSnapshot and its integration * Implement keyboard assigner and GTK3 key mapping TODO: controller configuration mapping and IGamepad implementation for keyboard * Add missing SR and SL definitions * Fix copy pasta mistake on config for previous commit * Implement IGamepad interface for GTK3 keyboard * Fix some implementation still being commented in the controller ui for keyboard * Port screen handle code * Remove all configuration management code and move HidNew to Hid * Rename InputConfigNew to InputConfig * Add a version field to the input config * Prepare serialization and deserialization of new input config and migrate profile loading and saving * Support input configuration saving to config and bump config version to 23. * Clean up in ConfigurationState * Reference SPB via a nuget package * Move new input system to Ryujinx.Input project and SDL2 detail to Ryujinx.Input.SDL2 * move GTK3 input to the right directory * Fix triggers on SDL2 * Update to SDL2 2.0.14 via our own fork * Update buttons definition for SDL2 2.0.14 and report gamepad features * Implement motion support again with SDL2 TODO: cemu hooks integration * Switch to latest of nightly SDL2 * SDL2: Fix bugs in gamepad id matching allowing different gamepad to match on the same device index * Ensure values are set in UI when the gamepad get hot plugged * Avoid trying to add controllers in the Update method and don't open SDL2 gamepad instance before checking ids This fixes permanent rumble of pro controller in some hotplug scenario * Fix more UI bugs * Move legcay motion code around before reintegration * gamecontroller UI tweaks here and there * Hide Motion on non motion configurations * Update the TODO grave Some TODO were fixed long time ago or are quite oudated... * Integrate cemu hooks motion configuration * Integrate cemu hooks configuration options to the UI again * cemuhooks => cemuhooks * Add cemu hook support again * Fix regression on normal motion and fix some very nasty bugs around * Fix for XCB multithreads issue on Linux * Enable motion by default * Block inputs in the main view when in the controller configuration window * Some fixes for the controller ui again * Add joycon support and fixes other hints * Bug fixes and clean up - Invert default mapping if not a Nintendo controller - Keep alive the controller being selected on the controller window (allow to avoid big delay for controller needing time to init when doing button assignment) - Clean up hints in use - Remove debug logs around - Fixes potential double free with SDL2Gamepad * Move the button assigner and motion logic to the Ryujinx.Input project * Reimplement raw keyboard hle input Also move out the logic of the hotkeys * Move all remaining Input manager stuffs to the Ryujinx.Input project * Increment configuration version yet again because of master changes * Ensure input config isn't null when not present * Fixes for VS not being nice * Fix broken gamepad caching logic causing crashes on ui * Ensure the background context is destroyed * Update dependencies * Readd retrocompat with old format of the config to avoid parsing and crashes on those versions Also updated the debug Config.json * Document new input APIs * Isolate SDL2Driver to the project and remove external export of it * Add support for external gamepad db mappings on SDL2 * Last clean up before PR * Addresses first part of comments * Address gdkchan's comments * Do not use JsonException * Last comment fixes
This commit is contained in:
parent
e13b15da75
commit
3b7c07c3c9
91 changed files with 4516 additions and 2048 deletions
|
@ -1,39 +1,37 @@
|
|||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Gdk;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OpenTK.Input;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Configuration;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using Ryujinx.Modules.Motion;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.Ui.Widgets;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
using Key = Ryujinx.Input.Key;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
using Switch = HLE.Switch;
|
||||
|
||||
public class GlRenderer : GLWidget
|
||||
{
|
||||
static GlRenderer()
|
||||
{
|
||||
OpenTK.Graphics.GraphicsContext.ShareContexts = true;
|
||||
}
|
||||
|
||||
private const int SwitchPanelWidth = 1280;
|
||||
private const int SwitchPanelHeight = 720;
|
||||
private const int TargetFps = 60;
|
||||
|
||||
public ManualResetEvent WaitEvent { get; set; }
|
||||
public NpadManager NpadManager { get; }
|
||||
|
||||
public static event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||
|
||||
|
@ -58,9 +56,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
private Renderer _renderer;
|
||||
|
||||
private HotkeyButtons _prevHotkeyButtons;
|
||||
|
||||
private Client _dsuClient;
|
||||
private KeyboardHotkeyState _prevHotkeyState;
|
||||
|
||||
private GraphicsDebugLevel _glLogLevel;
|
||||
|
||||
|
@ -71,14 +67,22 @@ namespace Ryujinx.Ui
|
|||
private static readonly Cursor _invisibleCursor = new Cursor(Display.Default, CursorType.BlankCursor);
|
||||
private long _lastCursorMoveTime;
|
||||
private bool _hideCursorOnIdle;
|
||||
private InputManager _inputManager;
|
||||
private IKeyboard _keyboardInterface;
|
||||
|
||||
public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel)
|
||||
public GlRenderer(Switch device, InputManager inputManager, GraphicsDebugLevel glLogLevel)
|
||||
: base (GetGraphicsMode(),
|
||||
3, 3,
|
||||
glLogLevel == GraphicsDebugLevel.None
|
||||
? GraphicsContextFlags.ForwardCompatible
|
||||
: GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
|
||||
? OpenGLContextFlags.Compat
|
||||
: OpenGLContextFlags.Compat | OpenGLContextFlags.Debug)
|
||||
{
|
||||
_inputManager = inputManager;
|
||||
NpadManager = _inputManager.CreateNpadManager();
|
||||
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
||||
|
||||
NpadManager.ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value.ToList());
|
||||
|
||||
WaitEvent = new ManualResetEvent(false);
|
||||
|
||||
_device = device;
|
||||
|
@ -101,8 +105,6 @@ namespace Ryujinx.Ui
|
|||
|
||||
Shown += Renderer_Shown;
|
||||
|
||||
_dsuClient = new Client();
|
||||
|
||||
_glLogLevel = glLogLevel;
|
||||
|
||||
_exitEvent = new ManualResetEvent(false);
|
||||
|
@ -130,15 +132,15 @@ namespace Ryujinx.Ui
|
|||
});
|
||||
}
|
||||
|
||||
private static GraphicsMode GetGraphicsMode()
|
||||
private static FramebufferFormat GetGraphicsMode()
|
||||
{
|
||||
return Environment.OSVersion.Platform == PlatformID.Unix ? new GraphicsMode(new ColorFormat(24)) : new GraphicsMode(new ColorFormat());
|
||||
return Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
|
||||
}
|
||||
|
||||
private void GLRenderer_ShuttingDown(object sender, EventArgs args)
|
||||
{
|
||||
_device.DisposeGpu();
|
||||
_dsuClient?.Dispose();
|
||||
NpadManager.Dispose();
|
||||
}
|
||||
|
||||
private void Parent_FocusOutEvent(object o, Gtk.FocusOutEventArgs args)
|
||||
|
@ -155,7 +157,7 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
ConfigurationState.Instance.HideCursorOnIdle.Event -= HideCursorStateChanged;
|
||||
|
||||
_dsuClient?.Dispose();
|
||||
NpadManager.Dispose();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
|
@ -164,13 +166,13 @@ namespace Ryujinx.Ui
|
|||
_isFocused = this.ParentWindow.State.HasFlag(Gdk.WindowState.Focused);
|
||||
}
|
||||
|
||||
public void HandleScreenState(KeyboardState keyboard)
|
||||
public void HandleScreenState(KeyboardStateSnapshot keyboard)
|
||||
{
|
||||
bool toggleFullscreen = keyboard.IsKeyDown(OpenTK.Input.Key.F11)
|
||||
|| ((keyboard.IsKeyDown(OpenTK.Input.Key.AltLeft)
|
||||
|| keyboard.IsKeyDown(OpenTK.Input.Key.AltRight))
|
||||
&& keyboard.IsKeyDown(OpenTK.Input.Key.Enter))
|
||||
|| keyboard.IsKeyDown(OpenTK.Input.Key.Escape);
|
||||
bool toggleFullscreen = keyboard.IsPressed(Key.F11)
|
||||
|| ((keyboard.IsPressed(Key.AltLeft)
|
||||
|| keyboard.IsPressed(Key.AltRight))
|
||||
&& keyboard.IsPressed(Key.Enter))
|
||||
|| keyboard.IsPressed(Key.Escape);
|
||||
|
||||
bool fullScreenToggled = ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen);
|
||||
|
||||
|
@ -185,7 +187,7 @@ namespace Ryujinx.Ui
|
|||
}
|
||||
else
|
||||
{
|
||||
if (keyboard.IsKeyDown(OpenTK.Input.Key.Escape))
|
||||
if (keyboard.IsPressed(Key.Escape))
|
||||
{
|
||||
if (!ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog())
|
||||
{
|
||||
|
@ -203,7 +205,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
_toggleFullscreen = toggleFullscreen;
|
||||
|
||||
bool toggleDockedMode = keyboard.IsKeyDown(OpenTK.Input.Key.F9);
|
||||
bool toggleDockedMode = keyboard.IsPressed(Key.F9);
|
||||
|
||||
if (toggleDockedMode != _toggleDockedMode)
|
||||
{
|
||||
|
@ -225,8 +227,8 @@ namespace Ryujinx.Ui
|
|||
|
||||
private void GLRenderer_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
// Release the GL exclusivity that OpenTK gave us as we aren't going to use it in GTK Thread.
|
||||
GraphicsContext.MakeCurrent(null);
|
||||
// Release the GL exclusivity that SPB gave us as we aren't going to use it in GTK Thread.
|
||||
OpenGLContext.MakeCurrent(null);
|
||||
|
||||
WaitEvent.Set();
|
||||
}
|
||||
|
@ -244,8 +246,6 @@ namespace Ryujinx.Ui
|
|||
|
||||
public void Start()
|
||||
{
|
||||
IsRenderHandler = true;
|
||||
|
||||
_chrono.Restart();
|
||||
|
||||
_isActive = true;
|
||||
|
@ -389,7 +389,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
public void Exit()
|
||||
{
|
||||
_dsuClient?.Dispose();
|
||||
NpadManager?.Dispose();
|
||||
|
||||
if (_isStopped)
|
||||
{
|
||||
|
@ -416,15 +416,17 @@ namespace Ryujinx.Ui
|
|||
public void Render()
|
||||
{
|
||||
// First take exclusivity on the OpenGL context.
|
||||
_renderer.InitializeBackgroundContext(GraphicsContext);
|
||||
_renderer.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(OpenGLContext));
|
||||
|
||||
Gtk.Window parent = Toplevel as Gtk.Window;
|
||||
parent.Present();
|
||||
GraphicsContext.MakeCurrent(WindowInfo);
|
||||
|
||||
OpenGLContext.MakeCurrent(NativeWindow);
|
||||
|
||||
_device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||
|
||||
// Make sure the first frame is not transparent.
|
||||
GL.ClearColor(OpenTK.Color.Black);
|
||||
GL.ClearColor(0, 0, 0, 1.0f);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
SwapBuffers();
|
||||
|
||||
|
@ -478,7 +480,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
OpenTK.Graphics.GraphicsContext.CurrentContext.SwapBuffers();
|
||||
NativeWindow.SwapBuffers();
|
||||
}
|
||||
|
||||
public void MainLoop()
|
||||
|
@ -510,13 +512,13 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
Gtk.Application.Invoke(delegate
|
||||
{
|
||||
KeyboardState keyboard = OpenTK.Input.Keyboard.GetState();
|
||||
KeyboardStateSnapshot keyboard = _keyboardInterface.GetKeyboardStateSnapshot();
|
||||
|
||||
HandleScreenState(keyboard);
|
||||
|
||||
if (keyboard.IsKeyDown(OpenTK.Input.Key.Delete))
|
||||
if (keyboard.IsPressed(Key.Delete))
|
||||
{
|
||||
if (!ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen))
|
||||
if (!ParentWindow.State.HasFlag(WindowState.Fullscreen))
|
||||
{
|
||||
Ptc.Continue();
|
||||
}
|
||||
|
@ -524,154 +526,19 @@ namespace Ryujinx.Ui
|
|||
});
|
||||
}
|
||||
|
||||
List<GamepadInput> gamepadInputs = new List<GamepadInput>(NpadDevices.MaxControllers);
|
||||
List<SixAxisInput> motionInputs = new List<SixAxisInput>(NpadDevices.MaxControllers);
|
||||
|
||||
MotionDevice motionDevice = new MotionDevice(_dsuClient);
|
||||
|
||||
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
|
||||
{
|
||||
ControllerKeys currentButton = 0;
|
||||
JoystickPosition leftJoystick = new JoystickPosition();
|
||||
JoystickPosition rightJoystick = new JoystickPosition();
|
||||
KeyboardInput? hidKeyboard = null;
|
||||
|
||||
int leftJoystickDx = 0;
|
||||
int leftJoystickDy = 0;
|
||||
int rightJoystickDx = 0;
|
||||
int rightJoystickDy = 0;
|
||||
|
||||
if (inputConfig.EnableMotion)
|
||||
{
|
||||
motionDevice.RegisterController(inputConfig.PlayerIndex);
|
||||
}
|
||||
|
||||
if (inputConfig is KeyboardConfig keyboardConfig)
|
||||
{
|
||||
if (_isFocused)
|
||||
{
|
||||
// Keyboard Input
|
||||
KeyboardController keyboardController = new KeyboardController(keyboardConfig);
|
||||
|
||||
currentButton = keyboardController.GetButtons();
|
||||
|
||||
(leftJoystickDx, leftJoystickDy) = keyboardController.GetLeftStick();
|
||||
(rightJoystickDx, rightJoystickDy) = keyboardController.GetRightStick();
|
||||
|
||||
leftJoystick = new JoystickPosition
|
||||
{
|
||||
Dx = leftJoystickDx,
|
||||
Dy = leftJoystickDy
|
||||
};
|
||||
|
||||
rightJoystick = new JoystickPosition
|
||||
{
|
||||
Dx = rightJoystickDx,
|
||||
Dy = rightJoystickDy
|
||||
};
|
||||
|
||||
if (ConfigurationState.Instance.Hid.EnableKeyboard)
|
||||
{
|
||||
hidKeyboard = keyboardController.GetKeysDown();
|
||||
}
|
||||
|
||||
if (!hidKeyboard.HasValue)
|
||||
{
|
||||
hidKeyboard = new KeyboardInput
|
||||
{
|
||||
Modifier = 0,
|
||||
Keys = new int[0x8]
|
||||
};
|
||||
}
|
||||
|
||||
if (ConfigurationState.Instance.Hid.EnableKeyboard)
|
||||
{
|
||||
_device.Hid.Keyboard.Update(hidKeyboard.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inputConfig is Common.Configuration.Hid.ControllerConfig controllerConfig)
|
||||
{
|
||||
// Controller Input
|
||||
JoystickController joystickController = new JoystickController(controllerConfig);
|
||||
|
||||
currentButton |= joystickController.GetButtons();
|
||||
|
||||
(leftJoystickDx, leftJoystickDy) = joystickController.GetLeftStick();
|
||||
(rightJoystickDx, rightJoystickDy) = joystickController.GetRightStick();
|
||||
|
||||
leftJoystick = new JoystickPosition
|
||||
{
|
||||
Dx = controllerConfig.LeftJoycon.InvertStickX ? -leftJoystickDx : leftJoystickDx,
|
||||
Dy = controllerConfig.LeftJoycon.InvertStickY ? -leftJoystickDy : leftJoystickDy
|
||||
};
|
||||
|
||||
rightJoystick = new JoystickPosition
|
||||
{
|
||||
Dx = controllerConfig.RightJoycon.InvertStickX ? -rightJoystickDx : rightJoystickDx,
|
||||
Dy = controllerConfig.RightJoycon.InvertStickY ? -rightJoystickDy : rightJoystickDy
|
||||
};
|
||||
}
|
||||
|
||||
currentButton |= _device.Hid.UpdateStickButtons(leftJoystick, rightJoystick);
|
||||
|
||||
motionDevice.Poll(inputConfig, inputConfig.Slot);
|
||||
|
||||
SixAxisInput sixAxisInput = new SixAxisInput()
|
||||
{
|
||||
PlayerId = (HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex,
|
||||
Accelerometer = motionDevice.Accelerometer,
|
||||
Gyroscope = motionDevice.Gyroscope,
|
||||
Rotation = motionDevice.Rotation,
|
||||
Orientation = motionDevice.Orientation
|
||||
};
|
||||
|
||||
motionInputs.Add(sixAxisInput);
|
||||
|
||||
gamepadInputs.Add(new GamepadInput
|
||||
{
|
||||
PlayerId = (HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex,
|
||||
Buttons = currentButton,
|
||||
LStick = leftJoystick,
|
||||
RStick = rightJoystick
|
||||
});
|
||||
|
||||
if (inputConfig.ControllerType == Common.Configuration.Hid.ControllerType.JoyconPair)
|
||||
{
|
||||
if (!inputConfig.MirrorInput)
|
||||
{
|
||||
motionDevice.Poll(inputConfig, inputConfig.AltSlot);
|
||||
|
||||
sixAxisInput = new SixAxisInput()
|
||||
{
|
||||
PlayerId = (HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex,
|
||||
Accelerometer = motionDevice.Accelerometer,
|
||||
Gyroscope = motionDevice.Gyroscope,
|
||||
Rotation = motionDevice.Rotation,
|
||||
Orientation = motionDevice.Orientation
|
||||
};
|
||||
}
|
||||
|
||||
motionInputs.Add(sixAxisInput);
|
||||
}
|
||||
}
|
||||
|
||||
_device.Hid.Npads.Update(gamepadInputs);
|
||||
_device.Hid.Npads.UpdateSixAxis(motionInputs);
|
||||
_device.TamperMachine.UpdateInput(gamepadInputs);
|
||||
NpadManager.Update(_device.Hid, _device.TamperMachine);
|
||||
|
||||
if(_isFocused)
|
||||
{
|
||||
// Hotkeys
|
||||
HotkeyButtons currentHotkeyButtons = KeyboardController.GetHotkeyButtons(OpenTK.Input.Keyboard.GetState());
|
||||
KeyboardHotkeyState currentHotkeyState = GetHotkeyState();
|
||||
|
||||
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
|
||||
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
|
||||
if (currentHotkeyState.HasFlag(KeyboardHotkeyState.ToggleVSync) &&
|
||||
!_prevHotkeyState.HasFlag(KeyboardHotkeyState.ToggleVSync))
|
||||
{
|
||||
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
|
||||
}
|
||||
|
||||
_prevHotkeyButtons = currentHotkeyButtons;
|
||||
_prevHotkeyState = currentHotkeyState;
|
||||
}
|
||||
|
||||
//Touchscreen
|
||||
|
@ -739,5 +606,24 @@ namespace Ryujinx.Ui
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum KeyboardHotkeyState
|
||||
{
|
||||
None,
|
||||
ToggleVSync
|
||||
}
|
||||
|
||||
private KeyboardHotkeyState GetHotkeyState()
|
||||
{
|
||||
KeyboardHotkeyState state = KeyboardHotkeyState.None;
|
||||
|
||||
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync))
|
||||
{
|
||||
state |= KeyboardHotkeyState.ToggleVSync;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
118
Ryujinx/Ui/GLWidget.cs
Normal file
118
Ryujinx/Ui/GLWidget.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using Gtk;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.GLX;
|
||||
using SPB.Platform.WGL;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
[ToolboxItem(true)]
|
||||
public class GLWidget : DrawingArea
|
||||
{
|
||||
private bool _initialized;
|
||||
|
||||
public event EventHandler Initialized;
|
||||
public event EventHandler ShuttingDown;
|
||||
|
||||
public OpenGLContextBase OpenGLContext { get; private set; }
|
||||
public NativeWindowBase NativeWindow { get; private set; }
|
||||
|
||||
public FramebufferFormat FramebufferFormat { get; }
|
||||
public int GLVersionMajor { get; }
|
||||
public int GLVersionMinor { get; }
|
||||
public OpenGLContextFlags ContextFlags { get; }
|
||||
|
||||
public bool DirectRendering { get; }
|
||||
public OpenGLContextBase SharedContext { get; }
|
||||
|
||||
public GLWidget(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase sharedContext = null)
|
||||
{
|
||||
FramebufferFormat = framebufferFormat;
|
||||
GLVersionMajor = major;
|
||||
GLVersionMinor = minor;
|
||||
ContextFlags = flags;
|
||||
DirectRendering = directRendering;
|
||||
SharedContext = sharedContext;
|
||||
}
|
||||
|
||||
protected override bool OnDrawn(Cairo.Context cr)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
Intialize();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private NativeWindowBase RetrieveNativeWindow()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
IntPtr windowHandle = gdk_win32_window_get_handle(Window.Handle);
|
||||
|
||||
return new WGLWindow(new NativeHandle(windowHandle));
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
IntPtr displayHandle = gdk_x11_display_get_xdisplay(Display.Handle);
|
||||
IntPtr windowHandle = gdk_x11_window_get_xid(Window.Handle);
|
||||
|
||||
return new GLXWindow(new NativeHandle(displayHandle), new NativeHandle(windowHandle));
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[DllImport("libgdk-3-0.dll")]
|
||||
private static extern IntPtr gdk_win32_window_get_handle(IntPtr d);
|
||||
|
||||
[DllImport("libgdk-3.so.0")]
|
||||
private static extern IntPtr gdk_x11_display_get_xdisplay(IntPtr gdkDisplay);
|
||||
|
||||
[DllImport("libgdk-3.so.0")]
|
||||
private static extern IntPtr gdk_x11_window_get_xid(IntPtr gdkWindow);
|
||||
|
||||
private void Intialize()
|
||||
{
|
||||
NativeWindow = RetrieveNativeWindow();
|
||||
|
||||
Window.EnsureNative();
|
||||
|
||||
OpenGLContext = PlatformHelper.CreateOpenGLContext(FramebufferFormat, GLVersionMajor, GLVersionMinor, ContextFlags, DirectRendering, SharedContext);
|
||||
|
||||
OpenGLContext.Initialize(NativeWindow);
|
||||
OpenGLContext.MakeCurrent(NativeWindow);
|
||||
|
||||
_initialized = true;
|
||||
|
||||
Initialized?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
// Try to bind the OpenGL context before calling the shutdown event
|
||||
try
|
||||
{
|
||||
OpenGLContext?.MakeCurrent(NativeWindow);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
ShuttingDown?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
// Unbind context and destroy everything
|
||||
try
|
||||
{
|
||||
OpenGLContext?.MakeCurrent(null);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
OpenGLContext.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using Ryujinx.Common.Configuration.Hid;
|
||||
|
||||
namespace Ryujinx.Ui.Input
|
||||
{
|
||||
interface ButtonAssigner
|
||||
{
|
||||
void Init();
|
||||
|
||||
void ReadInput();
|
||||
|
||||
bool HasAnyButtonPressed();
|
||||
|
||||
bool ShouldCancel();
|
||||
|
||||
string GetPressedButton();
|
||||
}
|
||||
}
|
|
@ -1,227 +0,0 @@
|
|||
using OpenTK.Input;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Ui.Input
|
||||
{
|
||||
class JoystickButtonAssigner : ButtonAssigner
|
||||
{
|
||||
private int _index;
|
||||
|
||||
private double _triggerThreshold;
|
||||
|
||||
private JoystickState _currState;
|
||||
|
||||
private JoystickState _prevState;
|
||||
|
||||
private JoystickButtonDetector _detector;
|
||||
|
||||
public JoystickButtonAssigner(int index, double triggerThreshold)
|
||||
{
|
||||
_index = index;
|
||||
_triggerThreshold = triggerThreshold;
|
||||
_detector = new JoystickButtonDetector();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_currState = Joystick.GetState(_index);
|
||||
_prevState = _currState;
|
||||
}
|
||||
|
||||
public void ReadInput()
|
||||
{
|
||||
_prevState = _currState;
|
||||
_currState = Joystick.GetState(_index);
|
||||
|
||||
CollectButtonStats();
|
||||
}
|
||||
|
||||
public bool HasAnyButtonPressed()
|
||||
{
|
||||
return _detector.HasAnyButtonPressed();
|
||||
}
|
||||
|
||||
public bool ShouldCancel()
|
||||
{
|
||||
return Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsAnyKeyDown;
|
||||
}
|
||||
|
||||
public string GetPressedButton()
|
||||
{
|
||||
List<ControllerInputId> pressedButtons = _detector.GetPressedButtons();
|
||||
|
||||
// Reverse list so axis button take precedence when more than one button is recognized.
|
||||
pressedButtons.Reverse();
|
||||
|
||||
return pressedButtons.Count > 0 ? pressedButtons[0].ToString() : "";
|
||||
}
|
||||
|
||||
private void CollectButtonStats()
|
||||
{
|
||||
JoystickCapabilities capabilities = Joystick.GetCapabilities(_index);
|
||||
|
||||
ControllerInputId pressedButton;
|
||||
|
||||
// Buttons
|
||||
for (int i = 0; i != capabilities.ButtonCount; i++)
|
||||
{
|
||||
if (_currState.IsButtonDown(i) && _prevState.IsButtonUp(i))
|
||||
{
|
||||
Enum.TryParse($"Button{i}", out pressedButton);
|
||||
_detector.AddInput(pressedButton, 1);
|
||||
}
|
||||
|
||||
if (_currState.IsButtonUp(i) && _prevState.IsButtonDown(i))
|
||||
{
|
||||
Enum.TryParse($"Button{i}", out pressedButton);
|
||||
_detector.AddInput(pressedButton, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Axis
|
||||
for (int i = 0; i != capabilities.AxisCount; i++)
|
||||
{
|
||||
float axisValue = _currState.GetAxis(i);
|
||||
|
||||
Enum.TryParse($"Axis{i}", out pressedButton);
|
||||
_detector.AddInput(pressedButton, axisValue);
|
||||
}
|
||||
|
||||
// Hats
|
||||
for (int i = 0; i != capabilities.HatCount; i++)
|
||||
{
|
||||
string currPos = GetHatPosition(_currState.GetHat((JoystickHat)i));
|
||||
string prevPos = GetHatPosition(_prevState.GetHat((JoystickHat)i));
|
||||
|
||||
if (currPos == prevPos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currPos != "")
|
||||
{
|
||||
Enum.TryParse($"Hat{i}{currPos}", out pressedButton);
|
||||
_detector.AddInput(pressedButton, 1);
|
||||
}
|
||||
|
||||
if (prevPos != "")
|
||||
{
|
||||
Enum.TryParse($"Hat{i}{prevPos}", out pressedButton);
|
||||
_detector.AddInput(pressedButton, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetHatPosition(JoystickHatState hatState)
|
||||
{
|
||||
if (hatState.IsUp) return "Up";
|
||||
if (hatState.IsDown) return "Down";
|
||||
if (hatState.IsLeft) return "Left";
|
||||
if (hatState.IsRight) return "Right";
|
||||
return "";
|
||||
}
|
||||
|
||||
private class JoystickButtonDetector
|
||||
{
|
||||
private Dictionary<ControllerInputId, InputSummary> _stats;
|
||||
|
||||
public JoystickButtonDetector()
|
||||
{
|
||||
_stats = new Dictionary<ControllerInputId, InputSummary>();
|
||||
}
|
||||
|
||||
public bool HasAnyButtonPressed()
|
||||
{
|
||||
foreach (var inputSummary in _stats.Values)
|
||||
{
|
||||
if (checkButtonPressed(inputSummary))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<ControllerInputId> GetPressedButtons()
|
||||
{
|
||||
List<ControllerInputId> pressedButtons = new List<ControllerInputId>();
|
||||
|
||||
foreach (var kvp in _stats)
|
||||
{
|
||||
if (!checkButtonPressed(kvp.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pressedButtons.Add(kvp.Key);
|
||||
}
|
||||
|
||||
return pressedButtons;
|
||||
}
|
||||
|
||||
public void AddInput(ControllerInputId button, float value)
|
||||
{
|
||||
InputSummary inputSummary;
|
||||
|
||||
if (!_stats.TryGetValue(button, out inputSummary))
|
||||
{
|
||||
inputSummary = new InputSummary();
|
||||
_stats.Add(button, inputSummary);
|
||||
}
|
||||
|
||||
inputSummary.AddInput(value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
TextWriter writer = new StringWriter();
|
||||
|
||||
foreach (var kvp in _stats)
|
||||
{
|
||||
writer.WriteLine($"Button {kvp.Key} -> {kvp.Value}");
|
||||
}
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
private bool checkButtonPressed(InputSummary sequence)
|
||||
{
|
||||
float distance = Math.Abs(sequence.Min - sequence.Avg) + Math.Abs(sequence.Max - sequence.Avg);
|
||||
return distance > 1.5; // distance range [0, 2]
|
||||
}
|
||||
}
|
||||
|
||||
private class InputSummary
|
||||
{
|
||||
public float Min, Max, Sum, Avg;
|
||||
|
||||
public int NumSamples;
|
||||
|
||||
public InputSummary()
|
||||
{
|
||||
Min = float.MaxValue;
|
||||
Max = float.MinValue;
|
||||
Sum = 0;
|
||||
NumSamples = 0;
|
||||
Avg = 0;
|
||||
}
|
||||
|
||||
public void AddInput(float value)
|
||||
{
|
||||
Min = Math.Min(Min, value);
|
||||
Max = Math.Max(Max, value);
|
||||
Sum += value;
|
||||
NumSamples += 1;
|
||||
Avg = Sum / NumSamples;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Avg: {Avg} Min: {Min} Max: {Max} Sum: {Sum} NumSamples: {NumSamples}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using OpenTK.Input;
|
||||
using System;
|
||||
using Key = Ryujinx.Configuration.Hid.Key;
|
||||
|
||||
namespace Ryujinx.Ui.Input
|
||||
{
|
||||
class KeyboardKeyAssigner : ButtonAssigner
|
||||
{
|
||||
private int _index;
|
||||
|
||||
private KeyboardState _keyboardState;
|
||||
|
||||
public KeyboardKeyAssigner(int index)
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
|
||||
public void Init() { }
|
||||
|
||||
public void ReadInput()
|
||||
{
|
||||
_keyboardState = KeyboardController.GetKeyboardState(_index);
|
||||
}
|
||||
|
||||
public bool HasAnyButtonPressed()
|
||||
{
|
||||
return _keyboardState.IsAnyKeyDown;
|
||||
}
|
||||
|
||||
public bool ShouldCancel()
|
||||
{
|
||||
return Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsKeyDown(OpenTK.Input.Key.Escape);
|
||||
}
|
||||
|
||||
public string GetPressedButton()
|
||||
{
|
||||
string keyPressed = "";
|
||||
|
||||
foreach (Key key in Enum.GetValues(typeof(Key)))
|
||||
{
|
||||
if (_keyboardState.IsKeyDown((OpenTK.Input.Key)key))
|
||||
{
|
||||
keyPressed = key.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !ShouldCancel() ? keyPressed : "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using System;
|
||||
|
||||
using ControllerConfig = Ryujinx.Common.Configuration.Hid.ControllerConfig;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
public class JoystickController
|
||||
{
|
||||
private readonly ControllerConfig _config;
|
||||
|
||||
public JoystickController(ControllerConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
private bool IsEnabled()
|
||||
{
|
||||
return Joystick.GetState(_config.Index).IsConnected;
|
||||
}
|
||||
|
||||
public ControllerKeys GetButtons()
|
||||
{
|
||||
// NOTE: This should be initialized AFTER GTK for compat reasons with OpenTK SDL2 backend and GTK on Linux.
|
||||
// BODY: Usage of Joystick.GetState must be defer to after GTK full initialization. Otherwise, GTK will segfault because SDL2 was already init *sighs*
|
||||
if (!IsEnabled())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
JoystickState joystickState = Joystick.GetState(_config.Index);
|
||||
|
||||
ControllerKeys buttons = 0;
|
||||
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.DPadUp)) buttons |= ControllerKeys.DpadUp;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.DPadDown)) buttons |= ControllerKeys.DpadDown;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.DPadLeft)) buttons |= ControllerKeys.DpadLeft;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.DPadRight)) buttons |= ControllerKeys.DpadRight;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.StickButton)) buttons |= ControllerKeys.LStick;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.ButtonMinus)) buttons |= ControllerKeys.Minus;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.ButtonL)) buttons |= ControllerKeys.L;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.ButtonZl)) buttons |= ControllerKeys.Zl;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.ButtonSl)) buttons |= ControllerKeys.SlLeft;
|
||||
if (IsActivated(joystickState, _config.LeftJoycon.ButtonSr)) buttons |= ControllerKeys.SrLeft;
|
||||
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonA)) buttons |= ControllerKeys.A;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonB)) buttons |= ControllerKeys.B;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonX)) buttons |= ControllerKeys.X;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonY)) buttons |= ControllerKeys.Y;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.StickButton)) buttons |= ControllerKeys.RStick;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonPlus)) buttons |= ControllerKeys.Plus;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonR)) buttons |= ControllerKeys.R;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonZr)) buttons |= ControllerKeys.Zr;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonSl)) buttons |= ControllerKeys.SlRight;
|
||||
if (IsActivated(joystickState, _config.RightJoycon.ButtonSr)) buttons |= ControllerKeys.SrRight;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private bool IsActivated(JoystickState joystickState, ControllerInputId controllerInputId)
|
||||
{
|
||||
if (controllerInputId <= ControllerInputId.Button20)
|
||||
{
|
||||
return joystickState.IsButtonDown((int)controllerInputId);
|
||||
}
|
||||
else if (controllerInputId <= ControllerInputId.Axis5)
|
||||
{
|
||||
int axis = controllerInputId - ControllerInputId.Axis0;
|
||||
|
||||
return joystickState.GetAxis(axis) > _config.TriggerThreshold;
|
||||
}
|
||||
else if (controllerInputId <= ControllerInputId.Hat2Right)
|
||||
{
|
||||
int hat = (controllerInputId - ControllerInputId.Hat0Up) / 4;
|
||||
|
||||
int baseHatId = (int)ControllerInputId.Hat0Up + (hat * 4);
|
||||
|
||||
JoystickHatState hatState = joystickState.GetHat((JoystickHat)hat);
|
||||
|
||||
if (hatState.IsUp && ((int)controllerInputId % baseHatId == 0)) return true;
|
||||
if (hatState.IsDown && ((int)controllerInputId % baseHatId == 1)) return true;
|
||||
if (hatState.IsLeft && ((int)controllerInputId % baseHatId == 2)) return true;
|
||||
if (hatState.IsRight && ((int)controllerInputId % baseHatId == 3)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public (short, short) GetLeftStick()
|
||||
{
|
||||
if (!IsEnabled())
|
||||
{
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
return GetStick(_config.LeftJoycon.StickX, _config.LeftJoycon.StickY, _config.DeadzoneLeft);
|
||||
}
|
||||
|
||||
public (short, short) GetRightStick()
|
||||
{
|
||||
if (!IsEnabled())
|
||||
{
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
return GetStick(_config.RightJoycon.StickX, _config.RightJoycon.StickY, _config.DeadzoneRight);
|
||||
}
|
||||
|
||||
private (short, short) GetStick(ControllerInputId stickXInputId, ControllerInputId stickYInputId, float deadzone)
|
||||
{
|
||||
if (stickXInputId < ControllerInputId.Axis0 || stickXInputId > ControllerInputId.Axis5 ||
|
||||
stickYInputId < ControllerInputId.Axis0 || stickYInputId > ControllerInputId.Axis5)
|
||||
{
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
JoystickState jsState = Joystick.GetState(_config.Index);
|
||||
|
||||
int xAxis = stickXInputId - ControllerInputId.Axis0;
|
||||
int yAxis = stickYInputId - ControllerInputId.Axis0;
|
||||
|
||||
float xValue = jsState.GetAxis(xAxis);
|
||||
float yValue = -jsState.GetAxis(yAxis); // Invert Y-axis
|
||||
|
||||
return ApplyDeadzone(new Vector2(xValue, yValue), deadzone);
|
||||
}
|
||||
|
||||
private (short, short) ApplyDeadzone(Vector2 axis, float deadzone)
|
||||
{
|
||||
return (ClampAxis(MathF.Abs(axis.X) > deadzone ? axis.X : 0f),
|
||||
ClampAxis(MathF.Abs(axis.Y) > deadzone ? axis.Y : 0f));
|
||||
}
|
||||
|
||||
private static short ClampAxis(float value)
|
||||
{
|
||||
if (value <= -short.MaxValue)
|
||||
{
|
||||
return -short.MaxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (short)(value * short.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Configuration;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
[Flags]
|
||||
public enum HotkeyButtons
|
||||
{
|
||||
ToggleVSync = 1 << 0,
|
||||
}
|
||||
|
||||
public class KeyboardController
|
||||
{
|
||||
private readonly KeyboardConfig _config;
|
||||
|
||||
public KeyboardController(KeyboardConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public static KeyboardState GetKeyboardState(int index)
|
||||
{
|
||||
if (index == KeyboardConfig.AllKeyboardsIndex || index < 0)
|
||||
{
|
||||
return Keyboard.GetState();
|
||||
}
|
||||
|
||||
return Keyboard.GetState(index - 1);
|
||||
}
|
||||
|
||||
public ControllerKeys GetButtons()
|
||||
{
|
||||
KeyboardState keyboard = GetKeyboardState(_config.Index);
|
||||
|
||||
ControllerKeys buttons = 0;
|
||||
|
||||
if (keyboard[(Key)_config.LeftJoycon.StickButton]) buttons |= ControllerKeys.LStick;
|
||||
if (keyboard[(Key)_config.LeftJoycon.DPadUp]) buttons |= ControllerKeys.DpadUp;
|
||||
if (keyboard[(Key)_config.LeftJoycon.DPadDown]) buttons |= ControllerKeys.DpadDown;
|
||||
if (keyboard[(Key)_config.LeftJoycon.DPadLeft]) buttons |= ControllerKeys.DpadLeft;
|
||||
if (keyboard[(Key)_config.LeftJoycon.DPadRight]) buttons |= ControllerKeys.DpadRight;
|
||||
if (keyboard[(Key)_config.LeftJoycon.ButtonMinus]) buttons |= ControllerKeys.Minus;
|
||||
if (keyboard[(Key)_config.LeftJoycon.ButtonL]) buttons |= ControllerKeys.L;
|
||||
if (keyboard[(Key)_config.LeftJoycon.ButtonZl]) buttons |= ControllerKeys.Zl;
|
||||
if (keyboard[(Key)_config.LeftJoycon.ButtonSl]) buttons |= ControllerKeys.SlLeft;
|
||||
if (keyboard[(Key)_config.LeftJoycon.ButtonSr]) buttons |= ControllerKeys.SrLeft;
|
||||
|
||||
if (keyboard[(Key)_config.RightJoycon.StickButton]) buttons |= ControllerKeys.RStick;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonA]) buttons |= ControllerKeys.A;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonB]) buttons |= ControllerKeys.B;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonX]) buttons |= ControllerKeys.X;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonY]) buttons |= ControllerKeys.Y;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonPlus]) buttons |= ControllerKeys.Plus;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonR]) buttons |= ControllerKeys.R;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonZr]) buttons |= ControllerKeys.Zr;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonSl]) buttons |= ControllerKeys.SlRight;
|
||||
if (keyboard[(Key)_config.RightJoycon.ButtonSr]) buttons |= ControllerKeys.SrRight;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public (short, short) GetLeftStick()
|
||||
{
|
||||
KeyboardState keyboard = GetKeyboardState(_config.Index);
|
||||
|
||||
short dx = 0;
|
||||
short dy = 0;
|
||||
|
||||
if (keyboard[(Key)_config.LeftJoycon.StickUp]) dy += 1;
|
||||
if (keyboard[(Key)_config.LeftJoycon.StickDown]) dy += -1;
|
||||
if (keyboard[(Key)_config.LeftJoycon.StickLeft]) dx += -1;
|
||||
if (keyboard[(Key)_config.LeftJoycon.StickRight]) dx += 1;
|
||||
|
||||
Vector2 stick = new Vector2(dx, dy);
|
||||
stick.NormalizeFast();
|
||||
|
||||
return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
|
||||
}
|
||||
|
||||
public (short, short) GetRightStick()
|
||||
{
|
||||
KeyboardState keyboard = GetKeyboardState(_config.Index);
|
||||
|
||||
short dx = 0;
|
||||
short dy = 0;
|
||||
|
||||
if (keyboard[(Key)_config.RightJoycon.StickUp]) dy += 1;
|
||||
if (keyboard[(Key)_config.RightJoycon.StickDown]) dy += -1;
|
||||
if (keyboard[(Key)_config.RightJoycon.StickLeft]) dx += -1;
|
||||
if (keyboard[(Key)_config.RightJoycon.StickRight]) dx += 1;
|
||||
|
||||
Vector2 stick = new Vector2(dx, dy);
|
||||
stick.NormalizeFast();
|
||||
|
||||
return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
|
||||
}
|
||||
|
||||
public static HotkeyButtons GetHotkeyButtons(KeyboardState keyboard)
|
||||
{
|
||||
HotkeyButtons buttons = 0;
|
||||
|
||||
if (keyboard[(Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync])
|
||||
{
|
||||
buttons |= HotkeyButtons.ToggleVSync;
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
class KeyMappingEntry
|
||||
{
|
||||
public Key TargetKey;
|
||||
public byte Target;
|
||||
}
|
||||
|
||||
private static readonly KeyMappingEntry[] KeyMapping = new KeyMappingEntry[]
|
||||
{
|
||||
new KeyMappingEntry { TargetKey = Key.A, Target = 0x4 },
|
||||
new KeyMappingEntry { TargetKey = Key.B, Target = 0x5 },
|
||||
new KeyMappingEntry { TargetKey = Key.C, Target = 0x6 },
|
||||
new KeyMappingEntry { TargetKey = Key.D, Target = 0x7 },
|
||||
new KeyMappingEntry { TargetKey = Key.E, Target = 0x8 },
|
||||
new KeyMappingEntry { TargetKey = Key.F, Target = 0x9 },
|
||||
new KeyMappingEntry { TargetKey = Key.G, Target = 0xA },
|
||||
new KeyMappingEntry { TargetKey = Key.H, Target = 0xB },
|
||||
new KeyMappingEntry { TargetKey = Key.I, Target = 0xC },
|
||||
new KeyMappingEntry { TargetKey = Key.J, Target = 0xD },
|
||||
new KeyMappingEntry { TargetKey = Key.K, Target = 0xE },
|
||||
new KeyMappingEntry { TargetKey = Key.L, Target = 0xF },
|
||||
new KeyMappingEntry { TargetKey = Key.M, Target = 0x10 },
|
||||
new KeyMappingEntry { TargetKey = Key.N, Target = 0x11 },
|
||||
new KeyMappingEntry { TargetKey = Key.O, Target = 0x12 },
|
||||
new KeyMappingEntry { TargetKey = Key.P, Target = 0x13 },
|
||||
new KeyMappingEntry { TargetKey = Key.Q, Target = 0x14 },
|
||||
new KeyMappingEntry { TargetKey = Key.R, Target = 0x15 },
|
||||
new KeyMappingEntry { TargetKey = Key.S, Target = 0x16 },
|
||||
new KeyMappingEntry { TargetKey = Key.T, Target = 0x17 },
|
||||
new KeyMappingEntry { TargetKey = Key.U, Target = 0x18 },
|
||||
new KeyMappingEntry { TargetKey = Key.V, Target = 0x19 },
|
||||
new KeyMappingEntry { TargetKey = Key.W, Target = 0x1A },
|
||||
new KeyMappingEntry { TargetKey = Key.X, Target = 0x1B },
|
||||
new KeyMappingEntry { TargetKey = Key.Y, Target = 0x1C },
|
||||
new KeyMappingEntry { TargetKey = Key.Z, Target = 0x1D },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.Number1, Target = 0x1E },
|
||||
new KeyMappingEntry { TargetKey = Key.Number2, Target = 0x1F },
|
||||
new KeyMappingEntry { TargetKey = Key.Number3, Target = 0x20 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number4, Target = 0x21 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number5, Target = 0x22 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number6, Target = 0x23 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number7, Target = 0x24 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number8, Target = 0x25 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number9, Target = 0x26 },
|
||||
new KeyMappingEntry { TargetKey = Key.Number0, Target = 0x27 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.Enter, Target = 0x28 },
|
||||
new KeyMappingEntry { TargetKey = Key.Escape, Target = 0x29 },
|
||||
new KeyMappingEntry { TargetKey = Key.BackSpace, Target = 0x2A },
|
||||
new KeyMappingEntry { TargetKey = Key.Tab, Target = 0x2B },
|
||||
new KeyMappingEntry { TargetKey = Key.Space, Target = 0x2C },
|
||||
new KeyMappingEntry { TargetKey = Key.Minus, Target = 0x2D },
|
||||
new KeyMappingEntry { TargetKey = Key.Plus, Target = 0x2E },
|
||||
new KeyMappingEntry { TargetKey = Key.BracketLeft, Target = 0x2F },
|
||||
new KeyMappingEntry { TargetKey = Key.BracketRight, Target = 0x30 },
|
||||
new KeyMappingEntry { TargetKey = Key.BackSlash, Target = 0x31 },
|
||||
new KeyMappingEntry { TargetKey = Key.Tilde, Target = 0x32 },
|
||||
new KeyMappingEntry { TargetKey = Key.Semicolon, Target = 0x33 },
|
||||
new KeyMappingEntry { TargetKey = Key.Quote, Target = 0x34 },
|
||||
new KeyMappingEntry { TargetKey = Key.Grave, Target = 0x35 },
|
||||
new KeyMappingEntry { TargetKey = Key.Comma, Target = 0x36 },
|
||||
new KeyMappingEntry { TargetKey = Key.Period, Target = 0x37 },
|
||||
new KeyMappingEntry { TargetKey = Key.Slash, Target = 0x38 },
|
||||
new KeyMappingEntry { TargetKey = Key.CapsLock, Target = 0x39 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.F1, Target = 0x3a },
|
||||
new KeyMappingEntry { TargetKey = Key.F2, Target = 0x3b },
|
||||
new KeyMappingEntry { TargetKey = Key.F3, Target = 0x3c },
|
||||
new KeyMappingEntry { TargetKey = Key.F4, Target = 0x3d },
|
||||
new KeyMappingEntry { TargetKey = Key.F5, Target = 0x3e },
|
||||
new KeyMappingEntry { TargetKey = Key.F6, Target = 0x3f },
|
||||
new KeyMappingEntry { TargetKey = Key.F7, Target = 0x40 },
|
||||
new KeyMappingEntry { TargetKey = Key.F8, Target = 0x41 },
|
||||
new KeyMappingEntry { TargetKey = Key.F9, Target = 0x42 },
|
||||
new KeyMappingEntry { TargetKey = Key.F10, Target = 0x43 },
|
||||
new KeyMappingEntry { TargetKey = Key.F11, Target = 0x44 },
|
||||
new KeyMappingEntry { TargetKey = Key.F12, Target = 0x45 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.PrintScreen, Target = 0x46 },
|
||||
new KeyMappingEntry { TargetKey = Key.ScrollLock, Target = 0x47 },
|
||||
new KeyMappingEntry { TargetKey = Key.Pause, Target = 0x48 },
|
||||
new KeyMappingEntry { TargetKey = Key.Insert, Target = 0x49 },
|
||||
new KeyMappingEntry { TargetKey = Key.Home, Target = 0x4A },
|
||||
new KeyMappingEntry { TargetKey = Key.PageUp, Target = 0x4B },
|
||||
new KeyMappingEntry { TargetKey = Key.Delete, Target = 0x4C },
|
||||
new KeyMappingEntry { TargetKey = Key.End, Target = 0x4D },
|
||||
new KeyMappingEntry { TargetKey = Key.PageDown, Target = 0x4E },
|
||||
new KeyMappingEntry { TargetKey = Key.Right, Target = 0x4F },
|
||||
new KeyMappingEntry { TargetKey = Key.Left, Target = 0x50 },
|
||||
new KeyMappingEntry { TargetKey = Key.Down, Target = 0x51 },
|
||||
new KeyMappingEntry { TargetKey = Key.Up, Target = 0x52 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.NumLock, Target = 0x53 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadDivide, Target = 0x54 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadMultiply, Target = 0x55 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadMinus, Target = 0x56 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadPlus, Target = 0x57 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadEnter, Target = 0x58 },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad1, Target = 0x59 },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad2, Target = 0x5A },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad3, Target = 0x5B },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad4, Target = 0x5C },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad5, Target = 0x5D },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad6, Target = 0x5E },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad7, Target = 0x5F },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad8, Target = 0x60 },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad9, Target = 0x61 },
|
||||
new KeyMappingEntry { TargetKey = Key.Keypad0, Target = 0x62 },
|
||||
new KeyMappingEntry { TargetKey = Key.KeypadPeriod, Target = 0x63 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.NonUSBackSlash, Target = 0x64 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.F13, Target = 0x68 },
|
||||
new KeyMappingEntry { TargetKey = Key.F14, Target = 0x69 },
|
||||
new KeyMappingEntry { TargetKey = Key.F15, Target = 0x6A },
|
||||
new KeyMappingEntry { TargetKey = Key.F16, Target = 0x6B },
|
||||
new KeyMappingEntry { TargetKey = Key.F17, Target = 0x6C },
|
||||
new KeyMappingEntry { TargetKey = Key.F18, Target = 0x6D },
|
||||
new KeyMappingEntry { TargetKey = Key.F19, Target = 0x6E },
|
||||
new KeyMappingEntry { TargetKey = Key.F20, Target = 0x6F },
|
||||
new KeyMappingEntry { TargetKey = Key.F21, Target = 0x70 },
|
||||
new KeyMappingEntry { TargetKey = Key.F22, Target = 0x71 },
|
||||
new KeyMappingEntry { TargetKey = Key.F23, Target = 0x72 },
|
||||
new KeyMappingEntry { TargetKey = Key.F24, Target = 0x73 },
|
||||
|
||||
new KeyMappingEntry { TargetKey = Key.ControlLeft, Target = 0xE0 },
|
||||
new KeyMappingEntry { TargetKey = Key.ShiftLeft, Target = 0xE1 },
|
||||
new KeyMappingEntry { TargetKey = Key.AltLeft, Target = 0xE2 },
|
||||
new KeyMappingEntry { TargetKey = Key.WinLeft, Target = 0xE3 },
|
||||
new KeyMappingEntry { TargetKey = Key.ControlRight, Target = 0xE4 },
|
||||
new KeyMappingEntry { TargetKey = Key.ShiftRight, Target = 0xE5 },
|
||||
new KeyMappingEntry { TargetKey = Key.AltRight, Target = 0xE6 },
|
||||
new KeyMappingEntry { TargetKey = Key.WinRight, Target = 0xE7 },
|
||||
};
|
||||
|
||||
private static readonly KeyMappingEntry[] KeyModifierMapping = new KeyMappingEntry[]
|
||||
{
|
||||
new KeyMappingEntry { TargetKey = Key.ControlLeft, Target = 0 },
|
||||
new KeyMappingEntry { TargetKey = Key.ShiftLeft, Target = 1 },
|
||||
new KeyMappingEntry { TargetKey = Key.AltLeft, Target = 2 },
|
||||
new KeyMappingEntry { TargetKey = Key.WinLeft, Target = 3 },
|
||||
new KeyMappingEntry { TargetKey = Key.ControlRight, Target = 4 },
|
||||
new KeyMappingEntry { TargetKey = Key.ShiftRight, Target = 5 },
|
||||
new KeyMappingEntry { TargetKey = Key.AltRight, Target = 6 },
|
||||
new KeyMappingEntry { TargetKey = Key.WinRight, Target = 7 },
|
||||
new KeyMappingEntry { TargetKey = Key.CapsLock, Target = 8 },
|
||||
new KeyMappingEntry { TargetKey = Key.ScrollLock, Target = 9 },
|
||||
new KeyMappingEntry { TargetKey = Key.NumLock, Target = 10 },
|
||||
};
|
||||
|
||||
public KeyboardInput GetKeysDown()
|
||||
{
|
||||
KeyboardState keyboard = GetKeyboardState(_config.Index);
|
||||
|
||||
KeyboardInput hidKeyboard = new KeyboardInput
|
||||
{
|
||||
Modifier = 0,
|
||||
Keys = new int[0x8]
|
||||
};
|
||||
|
||||
foreach (KeyMappingEntry entry in KeyMapping)
|
||||
{
|
||||
int value = keyboard[entry.TargetKey] ? 1 : 0;
|
||||
|
||||
hidKeyboard.Keys[entry.Target / 0x20] |= (value << (entry.Target % 0x20));
|
||||
}
|
||||
|
||||
foreach (KeyMappingEntry entry in KeyModifierMapping)
|
||||
{
|
||||
int value = keyboard[entry.TargetKey] ? 1 : 0;
|
||||
|
||||
hidKeyboard.Modifier |= value << entry.Target;
|
||||
}
|
||||
|
||||
return hidKeyboard;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@ using Ryujinx.HLE.FileSystem;
|
|||
using Ryujinx.HLE.FileSystem.Content;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.Input.GTK3;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.Input.SDL2;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.App;
|
||||
using Ryujinx.Ui.Applet;
|
||||
|
@ -65,6 +68,7 @@ namespace Ryujinx.Ui
|
|||
private bool _lastScannedAmiiboShowAll = false;
|
||||
|
||||
public GlRenderer GlRendererWidget;
|
||||
public InputManager InputManager;
|
||||
|
||||
#pragma warning disable CS0169, CS0649, IDE0044
|
||||
|
||||
|
@ -223,6 +227,8 @@ namespace Ryujinx.Ui
|
|||
};
|
||||
|
||||
Task.Run(RefreshFirmwareLabel);
|
||||
|
||||
InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver());
|
||||
}
|
||||
|
||||
private void WindowStateEvent_Changed(object o, WindowStateEventArgs args)
|
||||
|
@ -295,6 +301,11 @@ namespace Ryujinx.Ui
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroyed()
|
||||
{
|
||||
InputManager.Dispose();
|
||||
}
|
||||
|
||||
private void InitializeSwitchInstance()
|
||||
{
|
||||
_virtualFileSystem.Reload();
|
||||
|
@ -636,7 +647,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
DisplaySleep.Prevent();
|
||||
|
||||
GlRendererWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||
GlRendererWidget = new GlRenderer(_emulationContext, InputManager, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||
|
||||
Application.Invoke(delegate
|
||||
{
|
||||
|
|
20
Ryujinx/Ui/OpenToolkitBindingsContext.cs
Normal file
20
Ryujinx/Ui/OpenToolkitBindingsContext.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using SPB.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
public class OpenToolkitBindingsContext : OpenTK.IBindingsContext
|
||||
{
|
||||
private IBindingsContext _bindingContext;
|
||||
|
||||
public OpenToolkitBindingsContext(IBindingsContext bindingsContext)
|
||||
{
|
||||
_bindingContext = bindingsContext;
|
||||
}
|
||||
|
||||
public IntPtr GetProcAddress(string procName)
|
||||
{
|
||||
return _bindingContext.GetProcAddress(procName);
|
||||
}
|
||||
}
|
||||
}
|
49
Ryujinx/Ui/SPBOpenGLContext.cs
Normal file
49
Ryujinx/Ui/SPBOpenGLContext.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Windowing;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
class SPBOpenGLContext : IOpenGLContext
|
||||
{
|
||||
private OpenGLContextBase _context;
|
||||
private NativeWindowBase _window;
|
||||
|
||||
private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window)
|
||||
{
|
||||
_context = context;
|
||||
_window = window;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
_window.Dispose();
|
||||
}
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
_context.MakeCurrent(_window);
|
||||
}
|
||||
|
||||
public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext)
|
||||
{
|
||||
OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext);
|
||||
NativeWindowBase window = PlatformHelper.CreateWindow(FramebufferFormat.Default, 0, 0, 100, 100);
|
||||
|
||||
context.Initialize(window);
|
||||
context.MakeCurrent(window);
|
||||
|
||||
GL.LoadBindings(new OpenToolkitBindingsContext(context));
|
||||
|
||||
context.MakeCurrent(null);
|
||||
|
||||
return new SPBOpenGLContext(context, window);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -48,8 +48,8 @@
|
|||
<property name="title" translatable="yes">Ryujinx - Controller Settings</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="default_width">1150</property>
|
||||
<property name="default_height">690</property>
|
||||
<property name="default_width">1200</property>
|
||||
<property name="default_height">720</property>
|
||||
<child type="titlebar">
|
||||
<placeholder/>
|
||||
</child>
|
||||
|
@ -113,21 +113,6 @@
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="_refreshInputDevicesButton">
|
||||
<property name="label" translatable="yes">Refresh</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="margin_left">5</property>
|
||||
<signal name="toggled" handler="RefreshInputDevicesButton_Pressed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -682,7 +667,7 @@
|
|||
<property name="width_request">80</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">LStick Lt/Rt</property>
|
||||
<property name="label" translatable="yes">LStick</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -691,20 +676,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="width_request">80</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">LStick Up/Dn</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="_lStickX">
|
||||
<object class="GtkToggleButton" id="_lStick">
|
||||
<property name="label" translatable="yes"> </property>
|
||||
<property name="width_request">65</property>
|
||||
<property name="visible">True</property>
|
||||
|
@ -716,22 +688,9 @@
|
|||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="_lStickY">
|
||||
<property name="label" translatable="yes"> </property>
|
||||
<property name="width_request">65</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="_invertLStickX">
|
||||
<property name="label" translatable="yes">Invert</property>
|
||||
<property name="label" translatable="yes">Invert Stick X</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
|
@ -744,7 +703,7 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="_invertLStickY">
|
||||
<property name="label" translatable="yes">Invert</property>
|
||||
<property name="label" translatable="yes">Invert Stick Y</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
|
@ -1501,7 +1460,7 @@
|
|||
<property name="width_request">80</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">RStick Lt/Rt</property>
|
||||
<property name="label" translatable="yes">RStick</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -1510,20 +1469,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="width_request">80</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">RStick Up/Dn</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="_rStickX">
|
||||
<object class="GtkToggleButton" id="_rStick">
|
||||
<property name="label" translatable="yes"> </property>
|
||||
<property name="width_request">65</property>
|
||||
<property name="visible">True</property>
|
||||
|
@ -1535,22 +1481,9 @@
|
|||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="_rStickY">
|
||||
<property name="label" translatable="yes"> </property>
|
||||
<property name="width_request">65</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="_invertRStickX">
|
||||
<property name="label" translatable="yes">Invert</property>
|
||||
<property name="label" translatable="yes">Invert Stick X</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
|
@ -1563,7 +1496,7 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="_invertRStickY">
|
||||
<property name="label" translatable="yes">Invert</property>
|
||||
<property name="label" translatable="yes">Invert Stick Y</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
|
@ -1640,7 +1573,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="MotionBox">
|
||||
<object class="GtkBox" id="_motionBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
|
@ -1679,7 +1612,21 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<object class="GtkCheckButton" id="_enableCemuHook">
|
||||
<property name="label" translatable="yes">Use CemuHook compatible motion</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="_motionControllerSlot">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">10</property>
|
||||
|
@ -1718,7 +1665,7 @@
|
|||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1761,11 +1708,11 @@
|
|||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">3</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="_altBox">
|
||||
<object class="GtkBox" id="_motionAltBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
|
@ -1829,11 +1776,11 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<object class="GtkBox" id="_dsuServerHostBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">30</property>
|
||||
|
@ -1866,11 +1813,11 @@
|
|||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">5</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<object class="GtkBox" id="_dsuServerPortBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">30</property>
|
||||
|
@ -1903,7 +1850,7 @@
|
|||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">6</property>
|
||||
<property name="position">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1916,7 +1863,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">7</property>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1930,7 +1877,7 @@
|
|||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">8</property>
|
||||
<property name="position">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -578,7 +578,7 @@ namespace Ryujinx.Ui.Windows
|
|||
{
|
||||
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
||||
|
||||
ControllerWindow controllerWindow = new ControllerWindow(playerIndex);
|
||||
ControllerWindow controllerWindow = new ControllerWindow(_parent, playerIndex);
|
||||
|
||||
controllerWindow.SetSizeRequest((int)(controllerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(controllerWindow.DefaultHeight * Program.WindowScaleFactor));
|
||||
controllerWindow.Show();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue