using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Input; using System; using System.Collections.Generic; using System.Numerics; using ConfigKey = Ryujinx.Common.Configuration.Hid.Key; using Key = Ryujinx.Input.Key; namespace Ryujinx.Ava.Input { internal class AvaloniaKeyboard : IKeyboard { private readonly List _buttonsUserMapping; private readonly AvaloniaKeyboardDriver _driver; private StandardKeyboardInputConfig _configuration; private readonly object _userMappingLock = new(); public string Id { get; } public string Name { get; } public bool IsConnected => true; public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None; private class ButtonMappingEntry { public readonly Key From; public readonly GamepadButtonInputId To; public ButtonMappingEntry(GamepadButtonInputId to, Key from) { To = to; From = from; } } public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name) { _buttonsUserMapping = new List(); _driver = driver; Id = id; Name = name; } public KeyboardStateSnapshot GetKeyboardStateSnapshot() { return IKeyboard.GetStateSnapshot(this); } public GamepadStateSnapshot GetMappedStateSnapshot() { KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot(); GamepadStateSnapshot result = default; lock (_userMappingLock) { if (_configuration == null) { return result; } foreach (ButtonMappingEntry entry in _buttonsUserMapping) { if (entry.From == Key.Unknown || entry.From == Key.Unbound || entry.To == GamepadButtonInputId.Unbound) { continue; } // NOTE: Do not touch state of the button already pressed. if (!result.IsPressed(entry.To)) { result.SetPressed(entry.To, rawState.IsPressed(entry.From)); } } (short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick); (short rightStickX, short rightStickY) = GetStickValues(ref rawState, _configuration.RightJoyconStick); result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY)); result.SetStick(StickInputId.Right, ConvertRawStickValue(rightStickX), ConvertRawStickValue(rightStickY)); } return result; } public GamepadStateSnapshot GetStateSnapshot() { throw new NotSupportedException(); } public (float, float) GetStick(StickInputId inputId) { throw new NotSupportedException(); } public bool IsPressed(GamepadButtonInputId inputId) { throw new NotSupportedException(); } public bool IsPressed(Key key) { try { return _driver.IsPressed(key); } catch { return false; } } public void SetConfiguration(InputConfig configuration) { lock (_userMappingLock) { _configuration = (StandardKeyboardInputConfig)configuration; _buttonsUserMapping.Clear(); #pragma warning disable IDE0055 // Disable formatting // Left JoyCon _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl)); // Right JoyCon _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr)); _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl)); #pragma warning restore IDE0055 } } public void SetTriggerThreshold(float triggerThreshold) { } public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { } public Vector3 GetMotionData(MotionInputId inputId) => Vector3.Zero; private static float ConvertRawStickValue(short value) { const float ConvertRate = 1.0f / (short.MaxValue + 0.5f); return value * ConvertRate; } private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick stickConfig) { short stickX = 0; short stickY = 0; if (snapshot.IsPressed((Key)stickConfig.StickUp)) { stickY += 1; } if (snapshot.IsPressed((Key)stickConfig.StickDown)) { stickY -= 1; } if (snapshot.IsPressed((Key)stickConfig.StickRight)) { stickX += 1; } if (snapshot.IsPressed((Key)stickConfig.StickLeft)) { stickX -= 1; } Vector2 stick = new(stickX, stickY); stick = Vector2.Normalize(stick); return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue)); } public void Clear() { _driver?.ResetKeys(); } public void Dispose() { } } }