diff --git a/samples/GameMenu/GameMenu.csproj b/samples/GameMenu/GameMenu.csproj index 0852c38..09b40c3 100644 --- a/samples/GameMenu/GameMenu.csproj +++ b/samples/GameMenu/GameMenu.csproj @@ -1,4 +1,4 @@ - + Estragonia GameMenu Sample @@ -22,8 +22,8 @@ - - + + diff --git a/samples/HelloWorld/HelloWorld.csproj b/samples/HelloWorld/HelloWorld.csproj index 5e8065e..8066ed7 100644 --- a/samples/HelloWorld/HelloWorld.csproj +++ b/samples/HelloWorld/HelloWorld.csproj @@ -1,4 +1,4 @@ - + Estragonia HelloWorld Sample @@ -22,7 +22,7 @@ - + diff --git a/samples/HelloWorld/main.tscn b/samples/HelloWorld/main.tscn index 13bbe2a..8d53163 100644 --- a/samples/HelloWorld/main.tscn +++ b/samples/HelloWorld/main.tscn @@ -76,10 +76,10 @@ mesh = SubResource("BoxMesh_qchun") [node name="AnimationPlayer" type="AnimationPlayer" parent="."] root_node = NodePath("../Cube") -autoplay = "cube_rotation" libraries = { "": SubResource("AnimationLibrary_jucv5") } +autoplay = "cube_rotation" [node name="UserInterface" type="Control" parent="."] layout_mode = 3 diff --git a/samples/HelloWorld/project.godot b/samples/HelloWorld/project.godot index fd2e699..3e65a3a 100644 --- a/samples/HelloWorld/project.godot +++ b/samples/HelloWorld/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="HelloWorld" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.1", "C#", "Forward Plus") +config/features=PackedStringArray("4.2", "C#", "Forward Plus") config/icon="res://icon.svg" [autoload] diff --git a/src/JLeb.Estragonia/AvaloniaControl.cs b/src/JLeb.Estragonia/AvaloniaControl.cs index feb232e..9dbcfc4 100644 --- a/src/JLeb.Estragonia/AvaloniaControl.cs +++ b/src/JLeb.Estragonia/AvaloniaControl.cs @@ -9,7 +9,6 @@ using Godot.NativeInterop; using JLeb.Estragonia.Input; using AvControl = Avalonia.Controls.Control; -using AvDispatcher = Avalonia.Threading.Dispatcher; using GdControl = Godot.Control; using GdInput = Godot.Input; using GdKey = Godot.Key; diff --git a/src/JLeb.Estragonia/ConversionExtensions.cs b/src/JLeb.Estragonia/ConversionExtensions.cs index 5e19283..1285dfd 100644 --- a/src/JLeb.Estragonia/ConversionExtensions.cs +++ b/src/JLeb.Estragonia/ConversionExtensions.cs @@ -1,7 +1,7 @@ -using Avalonia; +using System.Collections.Generic; +using Avalonia; using Avalonia.Input; using Godot; -using Godot.Collections; using AvColor = Avalonia.Media.Color; using AvKey = Avalonia.Input.Key; using GdCursorShape = Godot.Control.CursorShape; @@ -140,6 +140,132 @@ public static class ConversionExtensions { [GdKey.Bar] = AvKey.Oem102 }; + private static readonly Dictionary s_physicalKeyMap = new() { + [GdKey.Backspace] = PhysicalKey.Backspace, + [GdKey.Tab] = PhysicalKey.Tab, // Godot maps Tab and CrSel to the same key + [GdKey.Clear] = PhysicalKey.NumPadClear, // Godot maps both Clear and OEM Clear to the same key + [GdKey.Enter] = PhysicalKey.Enter, + [GdKey.Shift] = PhysicalKey.ShiftLeft, // Godot maps Left Shift and Right Shift keys to the same key + [GdKey.Ctrl] = PhysicalKey.ControlLeft, // Godot maps Left Ctrl and Right Ctrl keys to the same key + [GdKey.Alt] = PhysicalKey.AltLeft, // Godot maps Left Alt and Right Alt keys to the same key + [GdKey.Pause] = PhysicalKey.Pause, + [GdKey.Capslock] = PhysicalKey.CapsLock, + [GdKey.Escape] = PhysicalKey.Escape, // Godot maps Escape and Attn keys to the same key + [GdKey.Space] = PhysicalKey.Space, + [GdKey.Pageup] = PhysicalKey.PageUp, + [GdKey.Pagedown] = PhysicalKey.PageDown, + [GdKey.End] = PhysicalKey.End, + [GdKey.Home] = PhysicalKey.Home, + [GdKey.Left] = PhysicalKey.ArrowLeft, + [GdKey.Up] = PhysicalKey.ArrowUp, + [GdKey.Right] = PhysicalKey.ArrowRight, + [GdKey.Down] = PhysicalKey.ArrowDown, + [GdKey.Print] = PhysicalKey.PrintScreen, // Godot maps Print and Snapshot keys to the same key + [GdKey.Insert] = PhysicalKey.Insert, + [GdKey.Delete] = PhysicalKey.Delete, + [GdKey.Help] = PhysicalKey.Help, + [GdKey.A] = PhysicalKey.A, + [GdKey.B] = PhysicalKey.B, + [GdKey.C] = PhysicalKey.C, + [GdKey.D] = PhysicalKey.D, + [GdKey.E] = PhysicalKey.E, + [GdKey.F] = PhysicalKey.F, + [GdKey.G] = PhysicalKey.G, + [GdKey.H] = PhysicalKey.H, + [GdKey.I] = PhysicalKey.I, + [GdKey.J] = PhysicalKey.J, + [GdKey.K] = PhysicalKey.K, + [GdKey.L] = PhysicalKey.L, + [GdKey.M] = PhysicalKey.M, + [GdKey.N] = PhysicalKey.N, + [GdKey.O] = PhysicalKey.O, + [GdKey.P] = PhysicalKey.P, + [GdKey.Q] = PhysicalKey.Q, + [GdKey.R] = PhysicalKey.R, + [GdKey.S] = PhysicalKey.S, + [GdKey.T] = PhysicalKey.T, + [GdKey.U] = PhysicalKey.U, + [GdKey.V] = PhysicalKey.V, + [GdKey.W] = PhysicalKey.W, + [GdKey.X] = PhysicalKey.X, + [GdKey.Y] = PhysicalKey.Y, + [GdKey.Z] = PhysicalKey.Z, + [GdKey.Meta] = PhysicalKey.MetaLeft, // Godot maps Left Win and Right Win keys to the same key + [GdKey.Menu] = PhysicalKey.ContextMenu, // Godot maps Left Menu and Right Menu keys to the same key + [GdKey.Standby] = PhysicalKey.Sleep, + [GdKey.Kp0] = PhysicalKey.NumPad0, + [GdKey.Kp1] = PhysicalKey.NumPad1, + [GdKey.Kp2] = PhysicalKey.NumPad2, + [GdKey.Kp3] = PhysicalKey.NumPad3, + [GdKey.Kp4] = PhysicalKey.NumPad4, + [GdKey.Kp5] = PhysicalKey.NumPad5, + [GdKey.Kp6] = PhysicalKey.NumPad6, + [GdKey.Kp7] = PhysicalKey.NumPad7, + [GdKey.Kp8] = PhysicalKey.NumPad8, + [GdKey.Kp9] = PhysicalKey.NumPad9, + [GdKey.KpMultiply] = PhysicalKey.NumPadMultiply, + [GdKey.KpAdd] = PhysicalKey.NumPadAdd, + [GdKey.KpSubtract] = PhysicalKey.NumPadSubtract, + [GdKey.KpPeriod] = PhysicalKey.NumPadDecimal, // Godot maps Separator and Decimal keys to the same key + [GdKey.KpDivide] = PhysicalKey.NumPadDivide, + [GdKey.F1] = PhysicalKey.F1, + [GdKey.F2] = PhysicalKey.F2, + [GdKey.F3] = PhysicalKey.F3, + [GdKey.F4] = PhysicalKey.F4, + [GdKey.F5] = PhysicalKey.F5, + [GdKey.F6] = PhysicalKey.F6, + [GdKey.F7] = PhysicalKey.F7, + [GdKey.F8] = PhysicalKey.F8, + [GdKey.F9] = PhysicalKey.F9, + [GdKey.F10] = PhysicalKey.F10, + [GdKey.F11] = PhysicalKey.F11, + [GdKey.F12] = PhysicalKey.F12, + [GdKey.F13] = PhysicalKey.F13, + [GdKey.F14] = PhysicalKey.F14, + [GdKey.F15] = PhysicalKey.F15, + [GdKey.F16] = PhysicalKey.F16, + [GdKey.F17] = PhysicalKey.F17, + [GdKey.F18] = PhysicalKey.F18, + [GdKey.F19] = PhysicalKey.F19, + [GdKey.F20] = PhysicalKey.F20, + [GdKey.F21] = PhysicalKey.F21, + [GdKey.F22] = PhysicalKey.F22, + [GdKey.F23] = PhysicalKey.F23, + [GdKey.F24] = PhysicalKey.F24, + [GdKey.Numlock] = PhysicalKey.NumLock, + [GdKey.Scrolllock] = PhysicalKey.ScrollLock, + [GdKey.Back] = PhysicalKey.BrowserBack, + [GdKey.Forward] = PhysicalKey.BrowserForward, + [GdKey.Refresh] = PhysicalKey.BrowserRefresh, + [GdKey.Stop] = PhysicalKey.BrowserStop, + [GdKey.Search] = PhysicalKey.BrowserSearch, + [GdKey.Favorites] = PhysicalKey.BrowserFavorites, + [GdKey.Homepage] = PhysicalKey.Home, + [GdKey.Volumemute] = PhysicalKey.AudioVolumeMute, + [GdKey.Volumedown] = PhysicalKey.AudioVolumeDown, + [GdKey.Volumeup] = PhysicalKey.AudioVolumeUp, + [GdKey.Medianext] = PhysicalKey.MediaTrackNext, + [GdKey.Mediaprevious] = PhysicalKey.MediaTrackPrevious, + [GdKey.Mediastop] = PhysicalKey.MediaStop, + [GdKey.Mediaplay] = PhysicalKey.MediaPlayPause, // Godot maps bot Media Play/Pause and Play keys to the same key + [GdKey.Launchmail] = PhysicalKey.LaunchMail, + [GdKey.Launchmedia] = PhysicalKey.MediaSelect, + [GdKey.Launch0] = PhysicalKey.LaunchApp1, + [GdKey.Launch1] = PhysicalKey.LaunchApp2, + [GdKey.Semicolon] = PhysicalKey.Semicolon, + [GdKey.Equal] = PhysicalKey.Equal, + [GdKey.Comma] = PhysicalKey.Comma, + [GdKey.Minus] = PhysicalKey.Minus, + [GdKey.Period] = PhysicalKey.Period, + [GdKey.Slash] = PhysicalKey.Slash, + [GdKey.Quoteleft] = PhysicalKey.Backquote, + [GdKey.Bracketleft] = PhysicalKey.BracketLeft, + [GdKey.Backslash] = PhysicalKey.Backslash, + [GdKey.Bracketright] = PhysicalKey.BracketRight, + [GdKey.Apostrophe] = PhysicalKey.Quote, + [GdKey.Bar] = PhysicalKey.IntlBackslash + }; + private static readonly Dictionary s_cursorMap = new() { [StandardCursorType.Arrow] = GdCursorShape.Arrow, [StandardCursorType.Ibeam] = GdCursorShape.Ibeam, @@ -167,7 +293,10 @@ public static class ConversionExtensions { }; public static AvKey ToAvaloniaKey(this GdKey source) - => s_keyMap.TryGetValue(source, out var result) ? result : AvKey.None; + => s_keyMap.GetValueOrDefault(source, AvKey.None); + + public static PhysicalKey ToAvaloniaPhysicalKey(this GdKey source) + => s_physicalKeyMap.GetValueOrDefault(source, PhysicalKey.None); public static Size ToAvaloniaSize(this Vector2 source) => new(source.X, source.Y); @@ -179,6 +308,6 @@ public static AvColor ToAvaloniaColor(this GdColor source) => new((byte) source.A8, (byte) source.R8, (byte) source.G8, (byte) source.B8); public static GdCursorShape ToGodotCursorShape(this StandardCursorType source) - => s_cursorMap.TryGetValue(source, out var result) ? result : GdCursorShape.Arrow; + => s_cursorMap.GetValueOrDefault(source, GdCursorShape.Arrow); } diff --git a/src/JLeb.Estragonia/GodotTopLevelImpl.cs b/src/JLeb.Estragonia/GodotTopLevelImpl.cs index c15c7cc..d5d4888 100644 --- a/src/JLeb.Estragonia/GodotTopLevelImpl.cs +++ b/src/JLeb.Estragonia/GodotTopLevelImpl.cs @@ -10,7 +10,6 @@ using Avalonia.Rendering.Composition; using Godot; using JLeb.Estragonia.Input; -using AvDispatcher = Avalonia.Threading.Dispatcher; using AvKey = Avalonia.Input.Key; using GdCursorShape = Godot.Control.CursorShape; using GdMouseButton = Godot.MouseButton; @@ -260,8 +259,8 @@ public bool OnKey(InputEventKey inputEvent, ulong timestamp) { var keyCode = inputEvent.Keycode; var pressed = inputEvent.Pressed; - var key = keyCode.ToAvaloniaKey(); + if (key != AvKey.None) { var args = new RawKeyEventArgs( GodotDevices.Keyboard, @@ -269,7 +268,9 @@ public bool OnKey(InputEventKey inputEvent, ulong timestamp) { _inputRoot, pressed ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, key, - inputEvent.GetRawInputModifiers() + inputEvent.GetRawInputModifiers(), + inputEvent.PhysicalKeycode.ToAvaloniaPhysicalKey(), + OS.GetKeycodeString(inputEvent.KeyLabel) ); input(args); @@ -300,8 +301,7 @@ public bool OnJoypadButton(InputEventJoypadButton inputEvent, ulong timestamp) { timestamp, _inputRoot, inputEvent.IsPressed() ? RawJoypadButtonEventType.ButtonDown : RawJoypadButtonEventType.ButtonUp, - inputEvent.ButtonIndex, - inputEvent.Pressure + inputEvent.ButtonIndex ); input(args); diff --git a/src/JLeb.Estragonia/Input/JoypadButtonEventArgs.cs b/src/JLeb.Estragonia/Input/JoypadButtonEventArgs.cs index 37721ac..4827e78 100644 --- a/src/JLeb.Estragonia/Input/JoypadButtonEventArgs.cs +++ b/src/JLeb.Estragonia/Input/JoypadButtonEventArgs.cs @@ -12,17 +12,10 @@ public class JoypadButtonEventArgs : RoutedEventArgs { /// Gets the button that was pressed or released. public JoyButton Button { get; } - /// - /// Gets the pressure the user puts on the button with their finger, if the controller supports it. - /// Ranges from 0 to 1. - /// - public float Pressure { get; } - - public JoypadButtonEventArgs(RoutedEvent? routedEvent, object? source, IJoypadDevice device, JoyButton button, float pressure) + public JoypadButtonEventArgs(RoutedEvent? routedEvent, object? source, IJoypadDevice device, JoyButton button) : base(routedEvent, source) { Device = device; Button = button; - Pressure = pressure; } } diff --git a/src/JLeb.Estragonia/Input/JoypadDevice.cs b/src/JLeb.Estragonia/Input/JoypadDevice.cs index 406985e..f48a364 100644 --- a/src/JLeb.Estragonia/Input/JoypadDevice.cs +++ b/src/JLeb.Estragonia/Input/JoypadDevice.cs @@ -35,7 +35,7 @@ private void ProcessButtonEvent(RawJoypadButtonEventArgs rawArgs) { return; var element = rawArgs.Root.FocusManager?.GetFocusedElement() ?? rawArgs.Root; - var args = new JoypadButtonEventArgs(routedEvent, element, this, rawArgs.Button, rawArgs.Pressure); + var args = new JoypadButtonEventArgs(routedEvent, element, this, rawArgs.Button); element.RaiseEvent(args); rawArgs.Handled = args.Handled; } diff --git a/src/JLeb.Estragonia/Input/RawJoypadButtonEventArgs.cs b/src/JLeb.Estragonia/Input/RawJoypadButtonEventArgs.cs index ddf23aa..d4e69dc 100644 --- a/src/JLeb.Estragonia/Input/RawJoypadButtonEventArgs.cs +++ b/src/JLeb.Estragonia/Input/RawJoypadButtonEventArgs.cs @@ -17,22 +17,14 @@ public class RawJoypadButtonEventArgs : RawInputEventArgs { /// Gets the button that was pressed or released. public JoyButton Button { get; } - /// - /// Gets the pressure the user puts on the button with their finger, if the controller supports it. - /// Ranges from 0 to 1. - /// - public float Pressure { get; } - public RawJoypadButtonEventArgs( IJoypadDevice device, ulong timestamp, IInputRoot root, RawJoypadButtonEventType type, - JoyButton button, - float pressure + JoyButton button ) : base(device, timestamp, root) { Button = button; - Pressure = pressure; Type = type; } diff --git a/src/JLeb.Estragonia/JLeb.Estragonia.csproj b/src/JLeb.Estragonia/JLeb.Estragonia.csproj index 2c7f491..5f29896 100644 --- a/src/JLeb.Estragonia/JLeb.Estragonia.csproj +++ b/src/JLeb.Estragonia/JLeb.Estragonia.csproj @@ -29,8 +29,8 @@ - - + +