From c5694985af64de79cbe982336ee3cdc2272998cd Mon Sep 17 00:00:00 2001 From: zhouzj Date: Mon, 7 Jul 2025 09:57:31 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=20AvaloniaXComponent=20?= =?UTF-8?q?=E5=92=8C=20XComponent=20=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 `AvaloniaXComponent.cs` 中新增了鼠标和悬停事件的处理方法。更新了类和方法的 XML 注释,改进了字段命名和 OpenGL ES 初始化逻辑, 在 `XComponent.cs` 中增加了构造函数和方法的注释,提升了代码的可读性和可维护性。 --- .../AvaloniaXComponent.cs | 224 ++++++++++++++---- Src/Avalonia.OpenHarmony/XComponent.cs | 75 +++++- 2 files changed, 238 insertions(+), 61 deletions(-) diff --git a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs index af1f62f..27fbe22 100644 --- a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs +++ b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs @@ -11,139 +11,201 @@ namespace Avalonia.OpenHarmony; +/// +/// 提供一个将 Avalonia 应用程序嵌入到 OpenHarmony XComponent 的实现。 +/// 此类处理 OpenGL ES 环境初始化、Avalonia 视图的创建、生命周期管理以及输入事件的分发。 +/// +/// 要运行的 Avalonia 应用程序类型,必须继承自 并有一个无参构造函数。 public class AvaloniaXComponent : XComponent where TApp : Application, new() { + // 输入设备 private readonly MouseDevice _mouseDevice; private readonly PenDevice _penDevice; - private readonly TouchDevice _touchDevice; - private nint display; - private EglInterface? egl; - private GL? gl; + + // EGL 和 OpenGL ES 相关字段 + private nint _display; + private EglInterface? _egl; + private GL? _gl; + private nint _surface; + + /// + /// Avalonia 控件的根容器。 + /// public EmbeddableControlRoot? Root; + + /// + /// 管理应用程序的生命周期,适用于单视图场景。 + /// public SingleViewLifetime? SingleViewLifetime; - private nint surface; + + /// + /// Avalonia 的顶层实现,处理渲染和输入。 + /// public TopLevelImpl? TopLevelImpl; + /// + /// 一个标志,用于指示是否应使用软件渲染器。 + /// 注意:此标志的当前实现逻辑可能与名称不完全匹配,因为它会触发 OpenGL 环境的初始化。 + /// public bool UseSoftRenderer = false; - public AvaloniaXComponent(nint XComponentHandle, nint WindowHandle) : base(XComponentHandle, WindowHandle) + /// + /// 初始化 类的新实例。 + /// + /// 原生 XComponent 的句柄。 + /// 窗口句柄。 + public AvaloniaXComponent(nint xComponentHandle, nint windowHandle) : base(xComponentHandle, windowHandle) { _touchDevice = new TouchDevice(); _penDevice = new PenDevice(); _mouseDevice = new MouseDevice(); } + /// + /// 初始化 OpenGL ES 环境。此方法设置 EGL 显示、配置、Surface和上下文。 + /// public void InitOpenGlEnv() { - egl = new EglInterface("libEGL.so"); + _egl = new EglInterface("libEGL.so"); - display = egl.GetDisplay(0); - if (egl.Initialize(display, out var major, out var minor) == false) + _display = _egl.GetDisplay(0); + if (_egl.Initialize(_display, out _, out _) == false) { - Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "egl.Initialize fail"); + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "CSharp", "_egl.Initialize fail"); return; } - Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "egl init success"); + Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "_egl init success"); + // EGL 配置属性,请求 RGBA8888 Surface和 OpenGL ES 2 兼容上下文 int[] attributes = [0x3033, 0x0004, 0x3024, 8, 0x3023, 8, 0x3022, 8, 0x3021, 8, 0x3040, 0x0004, 0x3038]; - if (egl.ChooseConfig(display, attributes, out var configs, 1, out var choosenConfig) == false) + if (_egl.ChooseConfig(_display, attributes, out var configs, 1, out _) == false) { - Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "egl.ChooseConfig fail"); + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "CSharp", "_egl.ChooseConfig fail"); return; } + // 窗口Surface属性 int[] winAttribs = [0x309D, 0x3089, 0x3038]; - surface = egl.CreateWindowSurface(display, configs, WindowHandle, winAttribs); - if (surface == 0) + _surface = _egl.CreateWindowSurface(_display, configs, WindowHandle, winAttribs); + if (_surface == 0) { - Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "egl.CreateWindowSurface fail"); + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "CSharp", "_egl.CreateWindowSurface fail"); return; } - + // EGL 上下文属性,指定 OpenGL ES 2.0 int[] attrib3_list = [0x3098, 2, 0x3038]; var sharedEglContext = 0; - var context = egl.CreateContext(display, configs, sharedEglContext, attrib3_list); - if (egl.MakeCurrent(display, surface, surface, context) == false) + var context = _egl.CreateContext(_display, configs, sharedEglContext, attrib3_list); + if (_egl.MakeCurrent(_display, _surface, _surface, context) == false) { - Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "CSharp", "egl.MakeCurrent fail"); + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "CSharp", "_egl.MakeCurrent fail"); return; } - - gl = GL.GetApi(name => + // 获取 OpenGL ES 函数指针 + _gl = GL.GetApi(name => { var ptr = Marshal.StringToHGlobalAnsi(name); - var fun = egl.GetProcAddress(ptr); + var fun = _egl.GetProcAddress(ptr); Marshal.FreeHGlobal(ptr); return fun; }); } + /// + /// 在 XComponent Surface创建时调用。 + /// 此方法初始化渲染环境(如果需要),配置并启动 Avalonia 应用程序。 + /// public override void OnSurfaceCreated() { - if (UseSoftRenderer) InitOpenGlEnv(); + if (UseSoftRenderer) + { + InitOpenGlEnv(); + } + var builder = CreateAppBuilder(); if (UseSoftRenderer) { builder.UseSoftwareRenderer(); - if (gl != null) AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); + if (_gl != null) + { + AvaloniaLocator.CurrentMutable.Bind().ToConstant(_gl); + } } SingleViewLifetime = new SingleViewLifetime(); builder.AfterApplicationSetup(CreateView).SetupWithLifetime(SingleViewLifetime); - Root?.StartRendering(); } + /// + /// 在 XComponent Surface上渲染一帧时调用。 + /// 此方法触发 Avalonia 的渲染逻辑,并在使用硬件渲染时交换缓冲区。 + /// + /// 当前帧的时间戳。 + /// 目标帧的时间戳。 public override void OnSurfaceRendered(ulong timestamp, ulong targetTimestamp) { if (TopLevelImpl == null) + { return; + } + base.OnSurfaceRendered(timestamp, targetTimestamp); TopLevelImpl.Render(); - if (UseSoftRenderer && egl != null) egl.SwapBuffers(display, surface); + if (UseSoftRenderer && _egl != null) + { + _egl.SwapBuffers(_display, _surface); + } } + /// + /// 创建 Avalonia 视图和相关的顶层实现。 + /// + /// 应用程序构建器。 private void CreateView(AppBuilder appBuilder) { if (SingleViewLifetime == null) + { return; + } + TopLevelImpl = new TopLevelImpl(XComponentHandle, WindowHandle); Root = new EmbeddableControlRoot(TopLevelImpl); SingleViewLifetime.Root = Root; Root.Prepare(); } + /// + /// 分发触摸事件。从原生 XComponent 获取触摸事件数据,并将其转换为 Avalonia 的输入事件。 + /// public override unsafe void DispatchTouchEvent() { - if (TopLevelImpl == null) - return; - if (TopLevelImpl.Input == null) - return; - if (TopLevelImpl.InputRoot == null) + if (TopLevelImpl == null || TopLevelImpl.Input == null || TopLevelImpl.InputRoot == null) + { return; + } + OH_NativeXComponent_TouchEvent touchEvent = default; var result = Ace.OH_NativeXComponent_GetTouchEvent((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &touchEvent); if (result == (int)OH_NATIVEXCOMPONENT_RESULT.SUCCESS) + { for (uint i = 0; i < touchEvent.numPoints; i++) { - OH_NativeXComponent_TouchPointToolType toolType = default; - float tiltX = 0; - float tiltY = 0; - - - Ace.OH_NativeXComponent_GetTouchPointToolType((OH_NativeXComponent*)XComponentHandle, i, &toolType); - Ace.OH_NativeXComponent_GetTouchPointTiltX((OH_NativeXComponent*)XComponentHandle, i, &tiltX); - Ace.OH_NativeXComponent_GetTouchPointTiltY((OH_NativeXComponent*)XComponentHandle, i, &tiltY); - + // 注意:toolType, tiltX, tiltY 当前未被使用。如果将来需要,可以取消注释或实现相关逻辑。 + // OH_NativeXComponent_TouchPointToolType toolType = default; + // float tiltX = 0; + // float tiltY = 0; + // _ = Ace.OH_NativeXComponent_GetTouchPointToolType((OH_NativeXComponent*)xComponentHandle, i, &toolType); + // _ = Ace.OH_NativeXComponent_GetTouchPointTiltX((OH_NativeXComponent*)xComponentHandle, i, &tiltX); + // _ = Ace.OH_NativeXComponent_GetTouchPointTiltY((OH_NativeXComponent*)xComponentHandle, i, &tiltY); var id = touchEvent.touchPoints[(int)i].id; - var type = touchEvent.touchPoints[(int)i].type switch { OH_NativeXComponent_TouchEventType.OH_NATIVEXCOMPONENT_DOWN => RawPointerEventType.TouchBegin, @@ -152,31 +214,95 @@ public override unsafe void DispatchTouchEvent() OH_NativeXComponent_TouchEventType.OH_NATIVEXCOMPONENT_CANCEL => RawPointerEventType.TouchCancel, _ => throw new NotImplementedException() }; - var position = new Point(touchEvent.touchPoints[(int)i].x, touchEvent.touchPoints[(int)i].y) / TopLevelImpl.RenderScaling; var modifiers = RawInputModifiers.None; - if (type == RawPointerEventType.TouchUpdate) modifiers |= RawInputModifiers.LeftMouseButton; + if (type == RawPointerEventType.TouchUpdate) + { + modifiers |= RawInputModifiers.LeftMouseButton; + } + var args = new RawTouchEventArgs(_touchDevice, (ulong)touchEvent.touchPoints[(int)i].timeStamp, TopLevelImpl.InputRoot, type, position, RawInputModifiers.LeftMouseButton, id); TopLevelImpl.Input?.Invoke(args); } + } else - Hilog.OH_LOG_ERROR(LogType.LOG_APP, "csharp", "OH_NativeXComponent_GetTouchEvent fail"); + { + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "csharp", $"OH_NativeXComponent_GetTouchEvent fail, result={result}"); + } } + /// + /// 分发鼠标事件。从原生 XComponent 获取鼠标事件数据,并将其转换为 Avalonia 的 RawPointerEventArgs, + /// 然后传递给顶层输入处理器。 + /// + public override unsafe void DispatchMouseEvent() + { + if (TopLevelImpl == null || TopLevelImpl.Input == null || TopLevelImpl.InputRoot == null) + { + return; + } + + OH_NativeXComponent_MouseEvent mouseEvent; + var result = Ace.OH_NativeXComponent_GetMouseEvent((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &mouseEvent); + + if (result == (int)OH_NATIVEXCOMPONENT_RESULT.SUCCESS) + { + var type = mouseEvent.action switch + { + OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_MOVE => RawPointerEventType.Move, + OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_PRESS => mouseEvent.button == OH_NativeXComponent_MouseEventButton.OH_NATIVEXCOMPONENT_LEFT_BUTTON ? RawPointerEventType.LeftButtonDown : RawPointerEventType.RightButtonDown, + OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_RELEASE => mouseEvent.button == OH_NativeXComponent_MouseEventButton.OH_NATIVEXCOMPONENT_LEFT_BUTTON ? RawPointerEventType.LeftButtonUp : RawPointerEventType.RightButtonUp, + _ => throw new NotImplementedException($"Mouse event action {mouseEvent.action} is not implemented") + }; + + var position = new Point(mouseEvent.x, mouseEvent.y) / TopLevelImpl.RenderScaling; + var modifiers = mouseEvent.button == OH_NativeXComponent_MouseEventButton.OH_NATIVEXCOMPONENT_LEFT_BUTTON ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; + + var args = new RawPointerEventArgs(_mouseDevice, (ulong)mouseEvent.timestamp, TopLevelImpl.InputRoot, type, position, modifiers); + + TopLevelImpl.Input?.Invoke(args); + } + else + { + Hilog.OH_LOG_ERROR(LogType.LOG_APP, "csharp", $"OH_NativeXComponent_GetMouseEvent fail, result={result}"); + } + } + + /// + /// 分发悬停事件。 + /// + /// 指示是否处于悬停状态。 + public override unsafe void DispatchHoverEvent(bool isHover) + { + // Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "csharp", $"DispatchHoverEvent isHover:{isHover}"); + } + + /// + /// 在 XComponent Surface尺寸或属性发生变化时调用。 + /// 此方法会调整顶层视图的大小,并更新 OpenGL 视口。 + /// public override unsafe void OnSurfaceChanged() { base.OnSurfaceChanged(); ulong width = 0, height = 0; - TopLevelImpl.Resize(); - Ace.OH_NativeXComponent_GetXComponentSize((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &width, + TopLevelImpl?.Resize(); + _ = Ace.OH_NativeXComponent_GetXComponentSize((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &width, &height); - if (UseSoftRenderer && gl != null) gl.Viewport(0, 0, (uint)width, (uint)height); + if (UseSoftRenderer && _gl != null) + { + _gl.Viewport(0, 0, (uint)width, (uint)height); + } } - private AppBuilder CreateAppBuilder() + /// + /// 创建并配置 Avalonia 应用程序构建器。 + /// 派生类可以重写此方法以提供自定义的应用程序配置。 + /// + /// 一个配置好的 实例。 + protected virtual AppBuilder CreateAppBuilder() { return AppBuilder.Configure().UseOpenHarmony(); } diff --git a/Src/Avalonia.OpenHarmony/XComponent.cs b/Src/Avalonia.OpenHarmony/XComponent.cs index 5843f2a..5766d60 100644 --- a/Src/Avalonia.OpenHarmony/XComponent.cs +++ b/Src/Avalonia.OpenHarmony/XComponent.cs @@ -1,46 +1,97 @@ -using OpenHarmony.NDK.Bindings.Native; +using OpenHarmony.NDK.Bindings.Native; namespace Avalonia.OpenHarmony; +/// +/// XComponent 封装了 OpenHarmony 原生 XComponent 的基本操作和生命周期事件。 +/// 用于管理与原生 XComponent 交互的句柄,并为派生类提供生命周期相关的虚方法。 +/// public class XComponent { - public XComponent(IntPtr XComponentHandle, IntPtr WindowHandle) + /// + /// 构造函数,初始化 XComponent 实例并保存原生句柄。 + /// + /// 原生 XComponent 句柄。 + /// 窗口句柄。 + public XComponent(IntPtr xComponentHandle, IntPtr windowHandle) { - this.XComponentHandle = XComponentHandle; - this.WindowHandle = WindowHandle; + XComponentHandle = xComponentHandle; + WindowHandle = windowHandle; } + /// + /// 获取原生 XComponent 句柄。 + /// public IntPtr XComponentHandle { get; } + + /// + /// 获取窗口句柄。 + /// public IntPtr WindowHandle { get; } + /// + /// 获取当前 XComponent 的尺寸。 + /// + /// 返回 Size 结构体,包含宽度和高度。 public virtual unsafe Size GetSize() { - ulong Width = 0; - ulong Height = 0; - Ace.OH_NativeXComponent_GetXComponentSize((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &Width, - &Height); - return new Size(Width, Height); + ulong width = 0; + ulong height = 0; + // 调用原生方法获取 XComponent 的宽高 + _ = Ace.OH_NativeXComponent_GetXComponentSize((OH_NativeXComponent*)XComponentHandle, (void*)WindowHandle, &width, + &height); + return new Size(width, height); } + /// + /// 当 XComponent Surface 创建时调用。可由派生类重写以实现自定义逻辑。 + /// public virtual void OnSurfaceCreated() { } - + /// + /// 当 XComponent Surface 销毁时调用。可由派生类重写以实现自定义逻辑。 + /// public virtual void OnSurfaceDestroyed() { } - + /// + /// 当 XComponent 渲染一帧时调用。可由派生类重写以实现自定义逻辑。 + /// + /// 当前帧时间戳。 + /// 目标帧时间戳。 public virtual void OnSurfaceRendered(ulong timestamp, ulong targetTimestamp) { } + /// + /// 当 XComponent Surface 发生变化(如尺寸变化)时调用。可由派生类重写。 + /// public virtual void OnSurfaceChanged() { } + /// + /// 分发触摸事件。可由派生类重写以处理触摸输入。 + /// public virtual void DispatchTouchEvent() { } -} \ No newline at end of file + + /// + /// 分发鼠标事件。可由派生类重写以处理鼠标输入。 + /// + public virtual void DispatchMouseEvent() + { + } + + /// + /// 分发鼠标悬停事件。可由派生类重写以处理悬停状态变化。 + /// + /// 是否悬停。 + public virtual void DispatchHoverEvent(bool isHover) + { + } +} From 4db8e72cc1c43f919f421b87148b3c41c9f0975e Mon Sep 17 00:00:00 2001 From: zhouzj Date: Mon, 7 Jul 2025 10:17:17 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=92=8C=E4=BF=AE=E5=A4=8D=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 `AvaloniaXComponent.cs` 中,`DispatchHoverEvent` 方法添加了调试日志记录的 TODO 注释,以便将来实现详细的日志记录功能。 在 `XComponentEntry.cs` 中,新增了两个静态方法 `DispatchMouseEvent` 和 `DispatchHoverEvent`,用于处理鼠标事件和悬停事件的分发,这些方法通过 `UnmanagedCallersOnly` 特性标记,以便从非托管代码调用。 在 `napi_init.cs` 中,添加了对鼠标事件回调的注册,包括 `DispatchMouseEvent` 和 `DispatchHoverEvent` 的回调指针,以支持鼠标事件的处理。 在 `MainView.axaml` 中,修复了 `UrsaView` 的 XML 命名空间声明,确保其正确性和完整性。 --- .../AvaloniaXComponent.cs | 1 + Src/Entry/XComponentEntry.cs | 21 +++++++++++++++++++ Src/Entry/napi_init.cs | 8 +++++++ Src/Example/AOOH_Gallery/Views/MainView.axaml | 3 ++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs index 27fbe22..936298c 100644 --- a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs +++ b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs @@ -277,6 +277,7 @@ public override unsafe void DispatchMouseEvent() /// 指示是否处于悬停状态。 public override unsafe void DispatchHoverEvent(bool isHover) { + // TODO // Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "csharp", $"DispatchHoverEvent isHover:{isHover}"); } diff --git a/Src/Entry/XComponentEntry.cs b/Src/Entry/XComponentEntry.cs index c937c9e..d15afb6 100644 --- a/Src/Entry/XComponentEntry.cs +++ b/Src/Entry/XComponentEntry.cs @@ -87,4 +87,25 @@ public static void DispatchTouchEvent(OH_NativeXComponent* component, void* wind return; xComponent.DispatchTouchEvent(); } + + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + public static void DispatchMouseEvent(OH_NativeXComponent* component, void* window) + { + if (XComponents.TryGetValue((nint)component, out var xComponent) == false) + { + return; + } + xComponent.DispatchMouseEvent(); + } + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + public static void DispatchHoverEvent(OH_NativeXComponent* component, bool isHover) + { + if (XComponents.TryGetValue((nint)component, out var xComponent) == false) + { + return; + } + xComponent.DispatchHoverEvent(isHover); + } } diff --git a/Src/Entry/napi_init.cs b/Src/Entry/napi_init.cs index 6e226ad..22e3942 100644 --- a/Src/Entry/napi_init.cs +++ b/Src/Entry/napi_init.cs @@ -59,6 +59,14 @@ public static unsafe napi_value Init(napi_env env, napi_value exports) g_ComponentCallback.OnSurfaceDestroyed = &XComponentEntry.OnSurfaceDestroyed; g_ComponentCallback.DispatchTouchEvent = &XComponentEntry.DispatchTouchEvent; Ace.OH_NativeXComponent_RegisterCallback(nativeXComponent, (OH_NativeXComponent_Callback*)p); + + + // 注册键盘事件回调 + var mouseEventCallbackPointer = Marshal.AllocHGlobal(sizeof(OH_NativeXComponent_MouseEvent_Callback)); + ref var g_ComponentMouseEventCallback = ref Unsafe.AsRef((void*)mouseEventCallbackPointer); + g_ComponentMouseEventCallback.DispatchMouseEvent = &XComponentEntry.DispatchMouseEvent; + g_ComponentMouseEventCallback.DispatchHoverEvent = &XComponentEntry.DispatchHoverEvent; + _ = Ace.OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, (OH_NativeXComponent_MouseEvent_Callback*)mouseEventCallbackPointer); } } diff --git a/Src/Example/AOOH_Gallery/Views/MainView.axaml b/Src/Example/AOOH_Gallery/Views/MainView.axaml index 2a2ca00..dbcea85 100644 --- a/Src/Example/AOOH_Gallery/Views/MainView.axaml +++ b/Src/Example/AOOH_Gallery/Views/MainView.axaml @@ -1,8 +1,9 @@ - Date: Mon, 7 Jul 2025 18:21:56 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20OpenHarmony.NET.Runtim?= =?UTF-8?q?e=20=E5=AD=90=E9=A1=B9=E7=9B=AE=E6=8F=90=E4=BA=A4=E8=AE=B0?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 替换原有提交记录 `6f9199df83bcb307d9f80e1e19f561f44cb32086` 为新的提交记录 `bfb1fed93e76fda1a24aed36e363ce09a23508cd`,可能包含代码或功能的更新与修复。 --- ThirdParty/OpenHarmony.NET.Runtime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThirdParty/OpenHarmony.NET.Runtime b/ThirdParty/OpenHarmony.NET.Runtime index 6f9199d..bfb1fed 160000 --- a/ThirdParty/OpenHarmony.NET.Runtime +++ b/ThirdParty/OpenHarmony.NET.Runtime @@ -1 +1 @@ -Subproject commit 6f9199df83bcb307d9f80e1e19f561f44cb32086 +Subproject commit bfb1fed93e76fda1a24aed36e363ce09a23508cd From 736e7b89307856b1e83368019690ba5e509b5cc6 Mon Sep 17 00:00:00 2001 From: zhouzj Date: Mon, 7 Jul 2025 20:14:00 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=BC=A0=E6=A0=87?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 `AvaloniaXComponent.cs` 文件中,添加了对鼠标事件的检查逻辑。如果 `mouseEvent.action` 为 `OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_NONE`,则直接返回,避免执行不必要的代码。这一改动提高了代码的效率和可读性。 --- Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs index 936298c..e940b8b 100644 --- a/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs +++ b/Src/Avalonia.OpenHarmony/AvaloniaXComponent.cs @@ -250,6 +250,11 @@ public override unsafe void DispatchMouseEvent() if (result == (int)OH_NATIVEXCOMPONENT_RESULT.SUCCESS) { + if (mouseEvent.action == OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_NONE) + { + return; // 如果没有鼠标事件,直接返回 + } + var type = mouseEvent.action switch { OH_NativeXComponent_MouseEventAction.OH_NATIVEXCOMPONENT_MOUSE_MOVE => RawPointerEventType.Move, From 5a20125982c36acd81c719a5e862d5ea5f2bda28 Mon Sep 17 00:00:00 2001 From: zhouzj Date: Wed, 16 Jul 2025 17:10:51 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95=E5=92=8C=E8=A7=A6=E6=91=B8?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 `OHDebugHelper.cs` 中添加了 `Error` 方法以记录错误日志,并重载了该方法以支持标题和异常信息。 在 `MainView.axaml` 中新增“触摸板和鼠标事件”选项卡,包含 `TouchAndMousePage` 视图。 在 `TouchAndMousePage.axaml` 中创建了新的用户控件,包含按钮和日志列表框,并设置了相应的布局和样式。 在 `TouchAndMousePage.axaml.cs` 中添加了多个指针事件处理程序,记录事件信息到日志,并实现了日志更新时自动滚动到列表框底部的功能。 --- Src/Avalonia.OpenHarmony/OHDebugHelper.cs | 5 + Src/Example/AOOH_Gallery/Views/MainView.axaml | 3 + .../Views/TouchAndMousePage.axaml | 33 ++++++ .../Views/TouchAndMousePage.axaml.cs | 111 ++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 Src/Example/AOOH_Gallery/Views/TouchAndMousePage.axaml create mode 100644 Src/Example/AOOH_Gallery/Views/TouchAndMousePage.axaml.cs diff --git a/Src/Avalonia.OpenHarmony/OHDebugHelper.cs b/Src/Avalonia.OpenHarmony/OHDebugHelper.cs index 6c04ab8..9a08e3f 100644 --- a/Src/Avalonia.OpenHarmony/OHDebugHelper.cs +++ b/Src/Avalonia.OpenHarmony/OHDebugHelper.cs @@ -16,6 +16,11 @@ public static void Debug(string log) AddLog(LogLevel.LOG_DEBUG, log); } + public static void Error(string log) + { + AddLog(LogLevel.LOG_ERROR, log); + } + public static void Error(string title, Exception exception) { AddLog(LogLevel.LOG_ERROR, $"{title}\n{exception}"); diff --git a/Src/Example/AOOH_Gallery/Views/MainView.axaml b/Src/Example/AOOH_Gallery/Views/MainView.axaml index de5fca7..d0c3ab8 100644 --- a/Src/Example/AOOH_Gallery/Views/MainView.axaml +++ b/Src/Example/AOOH_Gallery/Views/MainView.axaml @@ -51,6 +51,9 @@ + + + diff --git a/Src/Example/AOOH_Gallery/Views/TouchAndMousePage.axaml b/Src/Example/AOOH_Gallery/Views/TouchAndMousePage.axaml new file mode 100644 index 0000000..704b41d --- /dev/null +++ b/Src/Example/AOOH_Gallery/Views/TouchAndMousePage.axaml @@ -0,0 +1,33 @@ + + + + + + +