1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Fixed Windows input provider, Vulkan and logging

This commit is contained in:
Robert 2023-03-31 23:23:18 +02:00
parent 4518691907
commit 02e85af4af
8 changed files with 110 additions and 96 deletions

View File

@ -20,7 +20,7 @@ public static class UIContainerExtensions
public static void RegisterProviders(this IContainer container) public static void RegisterProviders(this IContainer container)
{ {
container.Register<ICursorProvider, CursorProvider>(Reuse.Singleton); container.Register<ICursorProvider, CursorProvider>(Reuse.Singleton);
// container.Register<IGraphicsContextProvider, GraphicsContextProvider>(Reuse.Singleton); container.Register<IGraphicsContextProvider, GraphicsContextProvider>(Reuse.Singleton);
container.Register<IAutoRunProvider, AutoRunProvider>(); container.Register<IAutoRunProvider, AutoRunProvider>();
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id); container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>(); container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>();

View File

@ -5,7 +5,7 @@ using System.Timers;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Windows.Utilities; using Artemis.UI.Windows.Utilities;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Platform;
using Avalonia.Platform; using Avalonia.Platform;
using Linearstar.Windows.RawInput; using Linearstar.Windows.RawInput;
using Linearstar.Windows.RawInput.Native; using Linearstar.Windows.RawInput.Native;
@ -15,35 +15,43 @@ namespace Artemis.UI.Windows.Providers.Input;
public class WindowsInputProvider : InputProvider public class WindowsInputProvider : InputProvider
{ {
private const int GWL_WNDPROC = -4;
private const int WM_INPUT = 0x00FF; private const int WM_INPUT = 0x00FF;
private readonly IWindowImpl _window;
private readonly nint _hWndProcHook;
private readonly WndProc? _fnWndProcHook;
private readonly IInputService _inputService; private readonly IInputService _inputService;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly Timer _taskManagerTimer; private readonly Timer _taskManagerTimer;
private int _lastProcessId; private int _lastProcessId;
delegate nint WndProc(nint hWnd, uint msg, nint wParam, nint lParam);
private nint CustomWndProc(nint hWnd, uint msg, nint wParam, nint lParam)
{
OnWndProcCalled(hWnd, msg, wParam, lParam);
return CallWindowProc(_hWndProcHook, hWnd, msg, wParam, lParam);
}
public WindowsInputProvider(ILogger logger, IInputService inputService) public WindowsInputProvider(ILogger logger, IInputService inputService)
{ {
_logger = logger; _logger = logger;
_inputService = inputService; _inputService = inputService;
_taskManagerTimer = new Timer(500); _taskManagerTimer = new Timer(500);
_taskManagerTimer.Elapsed += TaskManagerTimerOnElapsed; _taskManagerTimer.Elapsed += TaskManagerTimerOnElapsed;
_taskManagerTimer.Start(); _taskManagerTimer.Start();
// if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) _window = PlatformManager.CreateWindow();
// {
// IWindowImpl window = desktop.MainWindow!.PlatformImpl!; _hWndProcHook = GetWindowLongPtr(_window.Handle.Handle, GWL_WNDPROC);
// _fnWndProcHook = CustomWndProc;
// // https://github.com/sanjay900/guitar-configurator/blob/master/Notify/WindowsDeviceNotifierAvalonia.cs nint newLong = Marshal.GetFunctionPointerForDelegate(_fnWndProcHook);
// // _hWndProcHook = GetWindowLongPtr(window.Handle.Handle, GwlWndproc); SetWindowLongPtr(_window.Handle.Handle, GWL_WNDPROC, newLong);
// // _fnWndProcHook = CustomWndProc;
// // var newLong = Marshal.GetFunctionPointerForDelegate(_fnWndProcHook); RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard, RawInputDeviceFlags.InputSink, _window.Handle.Handle);
// // SetWindowLongPtr(window.Handle.Handle, GwlWndproc, newLong); RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, _window.Handle.Handle);
//
// RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard, RawInputDeviceFlags.InputSink, window.Handle.Handle);
// RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, window.Handle.Handle);
// }
} }
public static Guid Id { get; } = new("6737b204-ffb1-4cd9-8776-9fb851db303a"); public static Guid Id { get; } = new("6737b204-ffb1-4cd9-8776-9fb851db303a");
@ -256,6 +264,15 @@ public class WindowsInputProvider : InputProvider
#region Native #region Native
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CallWindowProc(nint lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Unicode)]
private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Unicode)]
private static extern IntPtr SetWindowLongPtr(nint hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll")] [DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(ref Win32Point pt); private static extern bool GetCursorPos(ref Win32Point pt);

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Avalonia.Controls; using Avalonia.Controls.Platform;
using Avalonia.Win32; using Avalonia.Platform;
using SharpVk; using SharpVk;
using SharpVk.Khronos; using SharpVk.Khronos;
@ -11,10 +11,10 @@ internal sealed class Win32VkContext : VkContext
{ {
public Win32VkContext() public Win32VkContext()
{ {
Window = new Window(); Window = PlatformManager.CreateWindow();
Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"}); Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"});
PhysicalDevice = Instance.EnumeratePhysicalDevices().First(); PhysicalDevice = Instance.EnumeratePhysicalDevices().First();
Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.PlatformImpl!.Handle.Handle); Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.Handle.Handle);
(GraphicsFamily, PresentFamily) = FindQueueFamilies(); (GraphicsFamily, PresentFamily) = FindQueueFamilies();
@ -44,12 +44,12 @@ internal sealed class Win32VkContext : VkContext
}; };
} }
public Window Window { get; } public IWindowImpl Window { get; }
public override void Dispose() public override void Dispose()
{ {
base.Dispose(); base.Dispose();
Window.Close(); Window.Dispose();
} }
private IntPtr Proc(string name, IntPtr instanceHandle, IntPtr deviceHandle) private IntPtr Proc(string name, IntPtr instanceHandle, IntPtr deviceHandle)

View File

@ -16,7 +16,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia" Version="11.0.0-preview6" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.0-preview5" />
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0-preview6" />
<PackageReference Include="Avalonia.Controls.Skia" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Controls.Skia" Version="11.0.0-preview6" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview6" />

View File

@ -16,7 +16,6 @@
Height="800"> Height="800">
<Window.Styles> <Window.Styles>
<StyleInclude Source="avares://AvaloniaEdit/AvaloniaEdit.xaml" />
<Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon"> <Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon">
<Setter Property="Margin" Value="-7 0 0 0" /> <Setter Property="Margin" Value="-7 0 0 0" />
</Style> </Style>

View File

@ -8,19 +8,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Debugger.Logs.LogsDebugView" x:Class="Artemis.UI.Screens.Debugger.Logs.LogsDebugView"
x:DataType="logs:LogsDebugViewModel"> x:DataType="logs:LogsDebugViewModel">
<aedit:TextEditor Name="LogTextEditor" <ScrollViewer Name="LogsScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
Document="{ CompiledBinding Document }" <SelectableTextBlock Inlines="{CompiledBinding Lines}" FontFamily="Consolas" SizeChanged="Control_OnSizeChanged"></SelectableTextBlock>
IsReadOnly="True" </ScrollViewer>
FontFamily="Consolas"
FontSize="12"
HorizontalScrollBarVisibility="Auto"
Padding="0 15 15 15"
TextChanged="OnTextChanged" >
<aedit:TextEditor.Styles>
<Style Selector="aedit|TextArea">
<Setter Property="SelectionBrush" Value="#44ffffff" />
</Style>
</aedit:TextEditor.Styles>
</aedit:TextEditor>
</UserControl> </UserControl>

View File

@ -1,7 +1,10 @@
using System; using System;
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
using ReactiveUI;
using Serilog;
namespace Artemis.UI.Screens.Debugger.Logs; namespace Artemis.UI.Screens.Debugger.Logs;
@ -19,36 +22,42 @@ public partial class LogsDebugView : ReactiveUserControl<LogsDebugViewModel>
protected override void OnInitialized() protected override void OnInitialized()
{ {
base.OnInitialized(); base.OnInitialized();
Dispatcher.UIThread.Post(() => LogTextEditor.ScrollToEnd(), DispatcherPriority.ApplicationIdle); Dispatcher.UIThread.Post(() => LogsScrollViewer.ScrollToEnd(), DispatcherPriority.ApplicationIdle);
} }
private void OnTextChanged(object? sender, EventArgs e) // private void OnTextChanged(object? sender, EventArgs e)
// {
// if (LogTextEditor.ExtentHeight == 0)
// return;
//
// int linesAdded = LogTextEditor.LineCount - _lineCount;
// double lineHeight = LogTextEditor.ExtentHeight / LogTextEditor.LineCount;
// double outOfScreenTextHeight = LogTextEditor.ExtentHeight - LogTextEditor.VerticalOffset - LogTextEditor.ViewportHeight;
// double outOfScreenLines = outOfScreenTextHeight / lineHeight;
//
// //we need this help distance because of rounding.
// //if we scroll slightly above the end, we still want it
// //to scroll down to the new lines.
// const double GRACE_DISTANCE = 1d;
//
// //if we were at the bottom of the log and
// //if the last log event was 5 lines long
// //we will be 5 lines out sync.
// //if this is the case, scroll down.
//
// //if we are more than that out of sync,
// //the user scrolled up and we should not
// //mess with anything.
// if (_lineCount == 0 || linesAdded + GRACE_DISTANCE > outOfScreenLines)
// {
// Dispatcher.UIThread.Post(() => LogTextEditor.ScrollToEnd(), DispatcherPriority.ApplicationIdle);
// _lineCount = LogTextEditor.LineCount;
// }
// }
private void Control_OnSizeChanged(object? sender, SizeChangedEventArgs e)
{ {
if (LogTextEditor.ExtentHeight == 0) if (!(LogsScrollViewer.Extent.Height - LogsScrollViewer.Offset.Y - LogsScrollViewer.Bounds.Bottom <= 60))
return; return;
Dispatcher.UIThread.Post(() => LogsScrollViewer.ScrollToEnd(), DispatcherPriority.Normal);
int linesAdded = LogTextEditor.LineCount - _lineCount;
double lineHeight = LogTextEditor.ExtentHeight / LogTextEditor.LineCount;
double outOfScreenTextHeight = LogTextEditor.ExtentHeight - LogTextEditor.VerticalOffset - LogTextEditor.ViewportHeight;
double outOfScreenLines = outOfScreenTextHeight / lineHeight;
//we need this help distance because of rounding.
//if we scroll slightly above the end, we still want it
//to scroll down to the new lines.
const double GRACE_DISTANCE = 1d;
//if we were at the bottom of the log and
//if the last log event was 5 lines long
//we will be 5 lines out sync.
//if this is the case, scroll down.
//if we are more than that out of sync,
//the user scrolled up and we should not
//mess with anything.
if (_lineCount == 0 || linesAdded + GRACE_DISTANCE > outOfScreenLines)
{
Dispatcher.UIThread.Post(() => LogTextEditor.ScrollToEnd(), DispatcherPriority.ApplicationIdle);
_lineCount = LogTextEditor.LineCount;
}
} }
} }

View File

@ -1,12 +1,15 @@
using Artemis.Core; using System;
using System.Collections.ObjectModel;
using Artemis.Core;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Avalonia.Threading; using Avalonia.Threading;
using AvaloniaEdit.Document;
using ReactiveUI; using ReactiveUI;
using Serilog.Events; using Serilog.Events;
using Serilog.Formatting.Display; using Serilog.Formatting.Display;
using System.IO; using System.IO;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls.Documents;
using Avalonia.Media;
namespace Artemis.UI.Screens.Debugger.Logs; namespace Artemis.UI.Screens.Debugger.Logs;
@ -14,38 +17,32 @@ public class LogsDebugViewModel : ActivatableViewModelBase
{ {
private readonly MessageTemplateTextFormatter _formatter; private readonly MessageTemplateTextFormatter _formatter;
public TextDocument Document { get; } public InlineCollection Lines { get; } = new InlineCollection();
private const int MAX_ENTRIES = 1000; private const int MAX_ENTRIES = 1000;
public LogsDebugViewModel() public LogsDebugViewModel()
{ {
DisplayName = "Logs"; DisplayName = "Logs";
Document = new TextDocument();
_formatter = new MessageTemplateTextFormatter( _formatter = new MessageTemplateTextFormatter(
"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}" "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
); );
foreach(LogEvent logEvent in LogStore.Events) foreach (LogEvent logEvent in LogStore.Events)
AddLogEvent(logEvent); AddLogEvent(logEvent);
this.WhenActivated(disp => this.WhenActivated(disp =>
{ {
LogStore.EventAdded += OnLogEventAdded; LogStore.EventAdded += OnLogEventAdded;
Disposable.Create(() => Disposable.Create(() => { LogStore.EventAdded -= OnLogEventAdded; }).DisposeWith(disp);
{
LogStore.EventAdded -= OnLogEventAdded;
}).DisposeWith(disp);
}); });
} }
private void OnLogEventAdded(object? sender, LogEventEventArgs e) private void OnLogEventAdded(object? sender, LogEventEventArgs e)
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() => { AddLogEvent(e.LogEvent); });
{
AddLogEvent(e.LogEvent);
});
} }
private void AddLogEvent(LogEvent? logEvent) private void AddLogEvent(LogEvent? logEvent)
@ -56,22 +53,27 @@ public class LogsDebugViewModel : ActivatableViewModelBase
using StringWriter writer = new(); using StringWriter writer = new();
_formatter.Format(logEvent, writer); _formatter.Format(logEvent, writer);
string line = writer.ToString(); string line = writer.ToString();
Document.Insert(Document.TextLength, '\n' + line.TrimEnd('\r', '\n'));
while (Document.LineCount > MAX_ENTRIES)
RemoveOldestLine(); Lines.Add(new Run(line.TrimEnd('\r', '\n') + '\n')
{
Foreground = logEvent.Level switch
{
LogEventLevel.Verbose => new SolidColorBrush(Colors.White),
LogEventLevel.Debug => new SolidColorBrush(Color.FromRgb(216, 216, 216)),
LogEventLevel.Information => new SolidColorBrush(Color.FromRgb(93, 201, 255)),
LogEventLevel.Warning => new SolidColorBrush(Color.FromRgb(255, 177, 53)),
LogEventLevel.Error => new SolidColorBrush(Color.FromRgb(255, 63, 63)),
LogEventLevel.Fatal => new SolidColorBrush(Colors.Red),
_ => throw new ArgumentOutOfRangeException()
}
});
LimitLines();
} }
private void RemoveOldestLine() private void LimitLines()
{ {
int firstNewLine = Document.IndexOf('\n', 0, Document.TextLength); if (Lines.Count > MAX_ENTRIES)
if (firstNewLine == -1) Lines.RemoveRange(0, Lines.Count - MAX_ENTRIES);
{
//this should never happen.
//just in case let's return
//instead of throwing
return;
}
Document.Remove(0, firstNewLine + 1);
} }
} }