forked from Mirror/Ryujinx
Add Direct Mouse Support (#2374)
* and direct mouse support * and direct mouse support * hide cursor if mouse enabled * add config * update docs * sorted usings
This commit is contained in:
parent
a10b2c5ff2
commit
77aab9aca3
16 changed files with 200 additions and 32 deletions
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
public MouseDevice(Switch device, bool active) : base(device, active) { }
|
public MouseDevice(Switch device, bool active) : base(device, active) { }
|
||||||
|
|
||||||
public void Update(int mouseX, int mouseY, uint buttons = 0, int scrollX = 0, int scrollY = 0)
|
public void Update(int mouseX, int mouseY, uint buttons = 0, int scrollX = 0, int scrollY = 0, bool connected = false)
|
||||||
{
|
{
|
||||||
ref RingLifo<MouseState> lifo = ref _device.Hid.SharedMemory.Mouse;
|
ref RingLifo<MouseState> lifo = ref _device.Hid.SharedMemory.Mouse;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
newState.DeltaY = mouseY - previousEntry.DeltaY;
|
newState.DeltaY = mouseY - previousEntry.DeltaY;
|
||||||
newState.WheelDeltaX = scrollX;
|
newState.WheelDeltaX = scrollX;
|
||||||
newState.WheelDeltaY = scrollY;
|
newState.WheelDeltaY = scrollY;
|
||||||
|
newState.Attributes = connected ? MouseAttribute.IsConnected : MouseAttribute.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
lifo.Write(ref newState);
|
lifo.Write(ref newState);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Ryujinx.Input.HLE
|
||||||
|
|
||||||
public NpadManager CreateNpadManager()
|
public NpadManager CreateNpadManager()
|
||||||
{
|
{
|
||||||
return new NpadManager(KeyboardDriver, GamepadDriver);
|
return new NpadManager(KeyboardDriver, GamepadDriver, MouseDriver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TouchScreenManager CreateTouchScreenManager()
|
public TouchScreenManager CreateTouchScreenManager()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid;
|
using Ryujinx.HLE.HOS.Services.Hid;
|
||||||
|
@ -6,7 +6,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
|
using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
|
||||||
|
@ -26,22 +25,23 @@ namespace Ryujinx.Input.HLE
|
||||||
|
|
||||||
private readonly IGamepadDriver _keyboardDriver;
|
private readonly IGamepadDriver _keyboardDriver;
|
||||||
private readonly IGamepadDriver _gamepadDriver;
|
private readonly IGamepadDriver _gamepadDriver;
|
||||||
|
private readonly IGamepadDriver _mouseDriver;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
|
||||||
private List<InputConfig> _inputConfig;
|
private List<InputConfig> _inputConfig;
|
||||||
private bool _enableKeyboard;
|
private bool _enableKeyboard;
|
||||||
|
private bool _enableMouse;
|
||||||
private Switch _device;
|
private Switch _device;
|
||||||
|
|
||||||
public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver)
|
public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver, IGamepadDriver mouseDriver)
|
||||||
{
|
{
|
||||||
_controllers = new NpadController[MaxControllers];
|
_controllers = new NpadController[MaxControllers];
|
||||||
_cemuHookClient = new CemuHookClient(this);
|
_cemuHookClient = new CemuHookClient(this);
|
||||||
|
|
||||||
_keyboardDriver = keyboardDriver;
|
_keyboardDriver = keyboardDriver;
|
||||||
_gamepadDriver = gamepadDriver;
|
_gamepadDriver = gamepadDriver;
|
||||||
|
_mouseDriver = mouseDriver;
|
||||||
_inputConfig = new List<InputConfig>();
|
_inputConfig = new List<InputConfig>();
|
||||||
_enableKeyboard = false;
|
|
||||||
|
|
||||||
_gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
_gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||||
_gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
_gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||||
|
@ -58,13 +58,13 @@ namespace Ryujinx.Input.HLE
|
||||||
private void HandleOnGamepadDisconnected(string obj)
|
private void HandleOnGamepadDisconnected(string obj)
|
||||||
{
|
{
|
||||||
// Force input reload
|
// Force input reload
|
||||||
ReloadConfiguration(_inputConfig, _enableKeyboard);
|
ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleOnGamepadConnected(string id)
|
private void HandleOnGamepadConnected(string id)
|
||||||
{
|
{
|
||||||
// Force input reload
|
// Force input reload
|
||||||
ReloadConfiguration(_inputConfig, _enableKeyboard);
|
ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -93,7 +93,7 @@ namespace Ryujinx.Input.HLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadConfiguration(List<InputConfig> inputConfig, bool enableKeyboard)
|
public void ReloadConfiguration(List<InputConfig> inputConfig, bool enableKeyboard, bool enableMouse)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
@ -119,8 +119,9 @@ namespace Ryujinx.Input.HLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_inputConfig = inputConfig;
|
_inputConfig = inputConfig;
|
||||||
_enableKeyboard = enableKeyboard;
|
_enableKeyboard = enableKeyboard;
|
||||||
|
_enableMouse = enableMouse;
|
||||||
|
|
||||||
_device.Hid.RefreshInputConfig(inputConfig);
|
_device.Hid.RefreshInputConfig(inputConfig);
|
||||||
}
|
}
|
||||||
|
@ -142,15 +143,15 @@ namespace Ryujinx.Input.HLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(Switch device, List<InputConfig> inputConfig, bool enableKeyboard)
|
public void Initialize(Switch device, List<InputConfig> inputConfig, bool enableKeyboard, bool enableMouse)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
_device.Configuration.RefreshInputConfig = RefreshInputConfigForHLE;
|
_device.Configuration.RefreshInputConfig = RefreshInputConfigForHLE;
|
||||||
|
|
||||||
ReloadConfiguration(inputConfig, enableKeyboard);
|
ReloadConfiguration(inputConfig, enableKeyboard, enableMouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update(float aspectRatio = 0)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
@ -206,6 +207,48 @@ namespace Ryujinx.Input.HLE
|
||||||
_device.Hid.Keyboard.Update(hleKeyboardInput.Value);
|
_device.Hid.Keyboard.Update(hleKeyboardInput.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_enableMouse)
|
||||||
|
{
|
||||||
|
var mouse = _mouseDriver.GetGamepad("0") as IMouse;
|
||||||
|
|
||||||
|
var mouseInput = IMouse.GetMouseStateSnapshot(mouse);
|
||||||
|
|
||||||
|
uint buttons = 0;
|
||||||
|
|
||||||
|
if (mouseInput.IsPressed(MouseButton.Button1))
|
||||||
|
{
|
||||||
|
buttons |= 1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseInput.IsPressed(MouseButton.Button2))
|
||||||
|
{
|
||||||
|
buttons |= 1 << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseInput.IsPressed(MouseButton.Button3))
|
||||||
|
{
|
||||||
|
buttons |= 1 << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseInput.IsPressed(MouseButton.Button4))
|
||||||
|
{
|
||||||
|
buttons |= 1 << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseInput.IsPressed(MouseButton.Button5))
|
||||||
|
{
|
||||||
|
buttons |= 1 << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = IMouse.GetScreenPosition(mouseInput.Position, mouse.ClientSize, aspectRatio);
|
||||||
|
|
||||||
|
_device.Hid.Mouse.Update((int)position.X, (int)position.Y, buttons, (int)mouseInput.Scroll.X, (int)mouseInput.Scroll.Y, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_device.Hid.Mouse.Update(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
_device.TamperMachine.UpdateInput(hleInputStates);
|
_device.TamperMachine.UpdateInput(hleInputStates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Ryujinx.Input.HLE
|
||||||
if (_wasClicking && !isClicking)
|
if (_wasClicking && !isClicking)
|
||||||
{
|
{
|
||||||
MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
|
MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
|
||||||
var touchPosition = IMouse.GetTouchPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
|
var touchPosition = IMouse.GetScreenPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
|
||||||
|
|
||||||
TouchPoint currentPoint = new TouchPoint
|
TouchPoint currentPoint = new TouchPoint
|
||||||
{
|
{
|
||||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Input.HLE
|
||||||
if (aspectRatio > 0)
|
if (aspectRatio > 0)
|
||||||
{
|
{
|
||||||
MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
|
MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
|
||||||
var touchPosition = IMouse.GetTouchPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
|
var touchPosition = IMouse.GetScreenPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
|
||||||
|
|
||||||
TouchAttribute attribute = TouchAttribute.None;
|
TouchAttribute attribute = TouchAttribute.None;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,11 @@ namespace Ryujinx.Input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Vector2 GetPosition();
|
Vector2 GetPosition();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the mouse scroll delta.
|
||||||
|
/// </summary>
|
||||||
|
Vector2 GetScroll();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the client size.
|
/// Get the client size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -40,22 +45,21 @@ namespace Ryujinx.Input
|
||||||
/// <returns>A snaphost of the state of the mouse.</returns>
|
/// <returns>A snaphost of the state of the mouse.</returns>
|
||||||
public static MouseStateSnapshot GetMouseStateSnapshot(IMouse mouse)
|
public static MouseStateSnapshot GetMouseStateSnapshot(IMouse mouse)
|
||||||
{
|
{
|
||||||
var position = mouse.GetPosition();
|
|
||||||
bool[] buttons = new bool[(int)MouseButton.Count];
|
bool[] buttons = new bool[(int)MouseButton.Count];
|
||||||
|
|
||||||
mouse.Buttons.CopyTo(buttons, 0);
|
mouse.Buttons.CopyTo(buttons, 0);
|
||||||
|
|
||||||
return new MouseStateSnapshot(buttons, position);
|
return new MouseStateSnapshot(buttons, mouse.GetPosition(), mouse.GetScroll());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the touch position of a mouse position relative to the app's view
|
/// Get the position of a mouse on screen relative to the app's view
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mousePosition">The position of the mouse in the client</param>
|
/// <param name="mousePosition">The position of the mouse in the client</param>
|
||||||
/// <param name="clientSize">The size of the client</param>
|
/// <param name="clientSize">The size of the client</param>
|
||||||
/// <param name="aspectRatio">The aspect ratio of the view</param>
|
/// <param name="aspectRatio">The aspect ratio of the view</param>
|
||||||
/// <returns>A snaphost of the state of the mouse.</returns>
|
/// <returns>A snaphost of the state of the mouse.</returns>
|
||||||
public static Vector2 GetTouchPosition(Vector2 mousePosition, Size clientSize, float aspectRatio)
|
public static Vector2 GetScreenPosition(Vector2 mousePosition, Size clientSize, float aspectRatio)
|
||||||
{
|
{
|
||||||
float mouseX = mousePosition.X;
|
float mouseX = mousePosition.X;
|
||||||
float mouseY = mousePosition.Y;
|
float mouseY = mousePosition.Y;
|
||||||
|
|
|
@ -10,17 +10,28 @@ namespace Ryujinx.Input
|
||||||
{
|
{
|
||||||
private bool[] _buttonState;
|
private bool[] _buttonState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position of the mouse cursor
|
||||||
|
/// </summary>
|
||||||
public Vector2 Position { get; }
|
public Vector2 Position { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The scroll delta of the mouse
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 Scroll { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="MouseStateSnapshot"/>.
|
/// Create a new <see cref="MouseStateSnapshot"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buttonState">The keys state</param>
|
/// <param name="buttonState">The button state</param>
|
||||||
public MouseStateSnapshot(bool[] buttonState, Vector2 position)
|
/// <param name="position">The position of the cursor</param>
|
||||||
|
/// <param name="scroll">The scroll delta</param>
|
||||||
|
public MouseStateSnapshot(bool[] buttonState, Vector2 position, Vector2 scroll)
|
||||||
{
|
{
|
||||||
_buttonState = buttonState;
|
_buttonState = buttonState;
|
||||||
|
|
||||||
Position = position;
|
Position = position;
|
||||||
|
Scroll = scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 24,
|
"version": 27,
|
||||||
"enable_file_log": true,
|
"enable_file_log": true,
|
||||||
"res_scale": 1,
|
"res_scale": 1,
|
||||||
"res_scale_custom": 1,
|
"res_scale_custom": 1,
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
"custom_theme_path": "",
|
"custom_theme_path": "",
|
||||||
"start_fullscreen": false,
|
"start_fullscreen": false,
|
||||||
"enable_keyboard": false,
|
"enable_keyboard": false,
|
||||||
|
"enable_mouse": false,
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"toggle_vsync": "Tab"
|
"toggle_vsync": "Tab"
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.Configuration
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 26;
|
public const int CurrentVersion = 27;
|
||||||
|
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
|
|
||||||
|
@ -224,6 +224,11 @@ namespace Ryujinx.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableKeyboard { get; set; }
|
public bool EnableKeyboard { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable mouse support (Independent from controllers binding)
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableMouse { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hotkey Keyboard Bindings
|
/// Hotkey Keyboard Bindings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -268,6 +268,11 @@ namespace Ryujinx.Configuration
|
||||||
/// Enable or disable keyboard support (Independent from controllers binding)
|
/// Enable or disable keyboard support (Independent from controllers binding)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> EnableKeyboard { get; private set; }
|
public ReactiveObject<bool> EnableKeyboard { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable mouse support (Independent from controllers binding)
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableMouse { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hotkey Keyboard Bindings
|
/// Hotkey Keyboard Bindings
|
||||||
|
@ -284,6 +289,7 @@ namespace Ryujinx.Configuration
|
||||||
public HidSection()
|
public HidSection()
|
||||||
{
|
{
|
||||||
EnableKeyboard = new ReactiveObject<bool>();
|
EnableKeyboard = new ReactiveObject<bool>();
|
||||||
|
EnableMouse = new ReactiveObject<bool>();
|
||||||
Hotkeys = new ReactiveObject<KeyboardHotkeys>();
|
Hotkeys = new ReactiveObject<KeyboardHotkeys>();
|
||||||
InputConfig = new ReactiveObject<List<InputConfig>>();
|
InputConfig = new ReactiveObject<List<InputConfig>>();
|
||||||
}
|
}
|
||||||
|
@ -471,6 +477,7 @@ namespace Ryujinx.Configuration
|
||||||
CustomThemePath = Ui.CustomThemePath,
|
CustomThemePath = Ui.CustomThemePath,
|
||||||
StartFullscreen = Ui.StartFullscreen,
|
StartFullscreen = Ui.StartFullscreen,
|
||||||
EnableKeyboard = Hid.EnableKeyboard,
|
EnableKeyboard = Hid.EnableKeyboard,
|
||||||
|
EnableMouse = Hid.EnableMouse,
|
||||||
Hotkeys = Hid.Hotkeys,
|
Hotkeys = Hid.Hotkeys,
|
||||||
KeyboardConfig = new List<object>(),
|
KeyboardConfig = new List<object>(),
|
||||||
ControllerConfig = new List<object>(),
|
ControllerConfig = new List<object>(),
|
||||||
|
@ -532,6 +539,7 @@ namespace Ryujinx.Configuration
|
||||||
Ui.CustomThemePath.Value = "";
|
Ui.CustomThemePath.Value = "";
|
||||||
Ui.StartFullscreen.Value = false;
|
Ui.StartFullscreen.Value = false;
|
||||||
Hid.EnableKeyboard.Value = false;
|
Hid.EnableKeyboard.Value = false;
|
||||||
|
Hid.EnableMouse.Value = false;
|
||||||
Hid.Hotkeys.Value = new KeyboardHotkeys
|
Hid.Hotkeys.Value = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = Key.Tab
|
ToggleVsync = Key.Tab
|
||||||
|
@ -828,6 +836,15 @@ namespace Ryujinx.Configuration
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 27)
|
||||||
|
{
|
||||||
|
Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableMouse = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||||
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||||
|
@ -878,6 +895,7 @@ namespace Ryujinx.Configuration
|
||||||
Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath;
|
Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath;
|
||||||
Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
|
Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
|
||||||
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
|
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
|
||||||
|
Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
|
||||||
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
|
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
|
||||||
Hid.InputConfig.Value = configurationFileFormat.InputConfig;
|
Hid.InputConfig.Value = configurationFileFormat.InputConfig;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,11 @@ namespace Ryujinx.Input.GTK3
|
||||||
return _driver.CurrentPosition;
|
return _driver.CurrentPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 GetScroll()
|
||||||
|
{
|
||||||
|
return _driver.Scroll;
|
||||||
|
}
|
||||||
|
|
||||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
@ -14,18 +14,27 @@ namespace Ryujinx.Input.GTK3
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
|
|
||||||
public Vector2 CurrentPosition { get; private set; }
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
|
public Vector2 Scroll{ get; private set; }
|
||||||
|
|
||||||
public GTK3MouseDriver(Widget parent)
|
public GTK3MouseDriver(Widget parent)
|
||||||
{
|
{
|
||||||
_widget = parent;
|
_widget = parent;
|
||||||
|
|
||||||
_widget.MotionNotifyEvent += Parent_MotionNotifyEvent;
|
_widget.MotionNotifyEvent += Parent_MotionNotifyEvent;
|
||||||
_widget.ButtonPressEvent += Parent_ButtonPressEvent;
|
_widget.ButtonPressEvent += Parent_ButtonPressEvent;
|
||||||
_widget.ButtonReleaseEvent += Parent_ButtonReleaseEvent;
|
_widget.ButtonReleaseEvent += Parent_ButtonReleaseEvent;
|
||||||
|
_widget.ScrollEvent += Parent_ScrollEvent;
|
||||||
|
|
||||||
PressedButtons = new bool[(int)MouseButton.Count];
|
PressedButtons = new bool[(int)MouseButton.Count];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[GLib.ConnectBefore]
|
||||||
|
private void Parent_ScrollEvent(object o, ScrollEventArgs args)
|
||||||
|
{
|
||||||
|
Scroll = new Vector2((float)args.Event.X, (float)args.Event.Y);
|
||||||
|
}
|
||||||
|
|
||||||
[GLib.ConnectBefore]
|
[GLib.ConnectBefore]
|
||||||
private void Parent_ButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
|
private void Parent_ButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private int _windowHeight;
|
private int _windowHeight;
|
||||||
private int _windowWidth;
|
private int _windowWidth;
|
||||||
|
private bool _isMouseInClient;
|
||||||
|
|
||||||
public RendererWidgetBase(InputManager inputManager, GraphicsDebugLevel glLogLevel)
|
public RendererWidgetBase(InputManager inputManager, GraphicsDebugLevel glLogLevel)
|
||||||
{
|
{
|
||||||
|
@ -87,6 +88,9 @@ namespace Ryujinx.Ui
|
||||||
AddEvents((int)(EventMask.ButtonPressMask
|
AddEvents((int)(EventMask.ButtonPressMask
|
||||||
| EventMask.ButtonReleaseMask
|
| EventMask.ButtonReleaseMask
|
||||||
| EventMask.PointerMotionMask
|
| EventMask.PointerMotionMask
|
||||||
|
| EventMask.ScrollMask
|
||||||
|
| EventMask.EnterNotifyMask
|
||||||
|
| EventMask.LeaveNotifyMask
|
||||||
| EventMask.KeyPressMask
|
| EventMask.KeyPressMask
|
||||||
| EventMask.KeyReleaseMask));
|
| EventMask.KeyReleaseMask));
|
||||||
|
|
||||||
|
@ -125,6 +129,8 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.HideCursorOnIdle.Event -= HideCursorStateChanged;
|
ConfigurationState.Instance.HideCursorOnIdle.Event -= HideCursorStateChanged;
|
||||||
|
|
||||||
|
Window.Cursor = null;
|
||||||
|
|
||||||
NpadManager.Dispose();
|
NpadManager.Dispose();
|
||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
@ -136,9 +142,34 @@ namespace Ryujinx.Ui
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ConfigurationState.Instance.Hid.EnableMouse)
|
||||||
|
{
|
||||||
|
Window.Cursor = _invisibleCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isMouseInClient = true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnEnterNotifyEvent(EventCrossing evnt)
|
||||||
|
{
|
||||||
|
Window.Cursor = ConfigurationState.Instance.Hid.EnableMouse ? _invisibleCursor : null;
|
||||||
|
|
||||||
|
_isMouseInClient = true;
|
||||||
|
|
||||||
|
return base.OnEnterNotifyEvent(evnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnLeaveNotifyEvent(EventCrossing evnt)
|
||||||
|
{
|
||||||
|
Window.Cursor = null;
|
||||||
|
|
||||||
|
_isMouseInClient = false;
|
||||||
|
|
||||||
|
return base.OnLeaveNotifyEvent(evnt);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnGetPreferredHeight(out int minimumHeight, out int naturalHeight)
|
protected override void OnGetPreferredHeight(out int minimumHeight, out int naturalHeight)
|
||||||
{
|
{
|
||||||
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
|
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
|
||||||
|
@ -241,11 +272,16 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
_toggleDockedMode = toggleDockedMode;
|
_toggleDockedMode = toggleDockedMode;
|
||||||
|
|
||||||
if (_hideCursorOnIdle)
|
if (_hideCursorOnIdle && !ConfigurationState.Instance.Hid.EnableMouse)
|
||||||
{
|
{
|
||||||
long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime;
|
long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime;
|
||||||
Window.Cursor = (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency) ? _invisibleCursor : null;
|
Window.Cursor = (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency) ? _invisibleCursor : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ConfigurationState.Instance.Hid.EnableMouse && _isMouseInClient)
|
||||||
|
{
|
||||||
|
Window.Cursor = _invisibleCursor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(Switch device)
|
public void Initialize(Switch device)
|
||||||
|
@ -254,7 +290,7 @@ namespace Ryujinx.Ui
|
||||||
Renderer = Device.Gpu.Renderer;
|
Renderer = Device.Gpu.Renderer;
|
||||||
Renderer?.Window.SetSize(_windowWidth, _windowHeight);
|
Renderer?.Window.SetSize(_windowWidth, _windowHeight);
|
||||||
|
|
||||||
NpadManager.Initialize(device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
|
NpadManager.Initialize(device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
TouchScreenManager.Initialize(device);
|
TouchScreenManager.Initialize(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +478,7 @@ namespace Ryujinx.Ui
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
NpadManager.Update();
|
NpadManager.Update(ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
||||||
|
|
||||||
if ((Toplevel as MainWindow).IsFocused)
|
if ((Toplevel as MainWindow).IsFocused)
|
||||||
{
|
{
|
||||||
|
@ -461,7 +497,7 @@ namespace Ryujinx.Ui
|
||||||
bool hasTouch = false;
|
bool hasTouch = false;
|
||||||
|
|
||||||
// Get screen touch position
|
// Get screen touch position
|
||||||
if ((Toplevel as MainWindow).IsFocused)
|
if ((Toplevel as MainWindow).IsFocused && !ConfigurationState.Instance.Hid.EnableMouse)
|
||||||
{
|
{
|
||||||
hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as GTK3MouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as GTK3MouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (_mainWindow.RendererWidget != null)
|
if (_mainWindow.RendererWidget != null)
|
||||||
{
|
{
|
||||||
_mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
|
_mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomically replace and signal input change.
|
// Atomically replace and signal input change.
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
[GUI] CheckButton _expandRamToggle;
|
[GUI] CheckButton _expandRamToggle;
|
||||||
[GUI] CheckButton _ignoreToggle;
|
[GUI] CheckButton _ignoreToggle;
|
||||||
[GUI] CheckButton _directKeyboardAccess;
|
[GUI] CheckButton _directKeyboardAccess;
|
||||||
|
[GUI] CheckButton _directMouseAccess;
|
||||||
[GUI] ComboBoxText _systemLanguageSelect;
|
[GUI] ComboBoxText _systemLanguageSelect;
|
||||||
[GUI] ComboBoxText _systemRegionSelect;
|
[GUI] ComboBoxText _systemRegionSelect;
|
||||||
[GUI] Entry _systemTimeZoneEntry;
|
[GUI] Entry _systemTimeZoneEntry;
|
||||||
|
@ -245,6 +246,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
_directKeyboardAccess.Click();
|
_directKeyboardAccess.Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConfigurationState.Instance.Hid.EnableMouse)
|
||||||
|
{
|
||||||
|
_directMouseAccess.Click();
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.EnableCustomTheme)
|
if (ConfigurationState.Instance.Ui.EnableCustomTheme)
|
||||||
{
|
{
|
||||||
_custThemeToggle.Click();
|
_custThemeToggle.Click();
|
||||||
|
@ -461,6 +467,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
ConfigurationState.Instance.System.ExpandRam.Value = _expandRamToggle.Active;
|
ConfigurationState.Instance.System.ExpandRam.Value = _expandRamToggle.Active;
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
|
||||||
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
|
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
|
||||||
|
ConfigurationState.Instance.Hid.EnableMouse.Value = _directMouseAccess.Active;
|
||||||
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
|
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
|
||||||
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
|
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
|
||||||
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Configuration.System.Region>(_systemRegionSelect.ActiveId);
|
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Configuration.System.Region>(_systemRegionSelect.ActiveId);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.38.1 -->
|
<!-- Generated with glade 3.38.2 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.20"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<object class="GtkAdjustment" id="_fsLogSpinAdjustment">
|
<object class="GtkAdjustment" id="_fsLogSpinAdjustment">
|
||||||
|
@ -520,6 +520,22 @@
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="_directMouseAccess">
|
||||||
|
<property name="label" translatable="yes">Direct Mouse Access</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">False</property>
|
||||||
|
<property name="tooltip-text" translatable="yes">Enable or disable "direct keyboard access (HID) support" (Provides games access to your keyboard as a text entry device)</property>
|
||||||
|
<property name="draw-indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="padding">10</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"enable_fs_integrity_checks",
|
"enable_fs_integrity_checks",
|
||||||
"fs_global_access_log_mode",
|
"fs_global_access_log_mode",
|
||||||
"enable_keyboard",
|
"enable_keyboard",
|
||||||
|
"enable_mouse",
|
||||||
"keyboard_config",
|
"keyboard_config",
|
||||||
"controller_config"
|
"controller_config"
|
||||||
],
|
],
|
||||||
|
@ -1438,6 +1439,17 @@
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"enable_mouse": {
|
||||||
|
"$id": "#/properties/enable_mouse",
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "(HID) Mouse Enable",
|
||||||
|
"description": "Enable or disable direct mouse access (HID) support (Provides games access to your mouse as a pointing device)",
|
||||||
|
"default": false,
|
||||||
|
"examples": [
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"$id": "#/properties/hotkeys",
|
"$id": "#/properties/hotkeys",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
Reference in a new issue