Forge
csharpdeeb25a2
1using System.Runtime.InteropServices;
2using System.Runtime.Versioning;
3using Avalonia.Controls;
4using Avalonia.Platform;
5using CascadeIDE.Features.Editor.Application.Monaco;
6using Microsoft.Web.WebView2.Core;
7
8namespace CascadeIDE.Features.Editor.Presentation;
9
10/// <summary>Maps vendored cide-editor assets to a https virtual host (WebView2 file:// breaks Monaco AMD).</summary>
11internal static class MonacoEditorWebViewBootstrap
12{
13 private const int VkP = 0x50;
14 private const int VkControl = 0x11;
15
16 public static bool TryMapVirtualHost(NativeWebView webView) =>
17 TryConfigure(webView, onHostShortcut: null);
18
19 public static bool TryConfigure(NativeWebView webView, Action<string>? onHostShortcut)
20 {
21 if (!OperatingSystem.IsWindows())
22 return false;
23
24 return TryConfigureWindows(webView, onHostShortcut);
25 }
26
27 [SupportedOSPlatform("windows")]
28 private static bool TryConfigureWindows(NativeWebView webView, Action<string>? onHostShortcut)
29 {
30 if (webView.TryGetPlatformHandle() is not IWindowsWebView2PlatformHandle win)
31 return false;
32
33 var core = TryGetCoreWebView2(win);
34 if (core is null)
35 return false;
36
37 var root = MonacoEditorAssetLocator.GetCideEditorRoot();
38 if (!Directory.Exists(root))
39 return false;
40
41 core.SetVirtualHostNameToFolderMapping(
42 MonacoEditorAssetLocator.VirtualHostName,
43 root,
44 CoreWebView2HostResourceAccessKind.Allow);
45
46 if (onHostShortcut is not null
47 && TryGetCoreWebView2Controller(win) is { } controller)
48 {
49 core.Settings.AreBrowserAcceleratorKeysEnabled = false;
50 controller.AcceleratorKeyPressed += (_, e) =>
51 {
52 if (!IsCtrlPKeyDown(e))
53 return;
54
55 e.Handled = true;
56 onHostShortcut("workspace_go_to_file");
57 };
58 }
59
60 return true;
61 }
62
63 [SupportedOSPlatform("windows")]
64 private static bool IsCtrlPKeyDown(CoreWebView2AcceleratorKeyPressedEventArgs e)
65 {
66 if (e.VirtualKey != VkP)
67 return false;
68
69 if (e.PhysicalKeyStatus.IsKeyReleased != 0)
70 return false;
71
72 var lParam = e.KeyEventLParam;
73 if ((lParam & (1 << 31)) != 0)
74 return false;
75
76 if ((lParam & (1 << 30)) != 0)
77 return false;
78
79 return (GetKeyState(VkControl) & 0x8000) != 0;
80 }
81
82 [DllImport("user32.dll")]
83 private static extern short GetKeyState(int nVirtKey);
84
85 [SupportedOSPlatform("windows")]
86 private static CoreWebView2? TryGetCoreWebView2(IWindowsWebView2PlatformHandle handle)
87 {
88 if (handle.CoreWebView2 == IntPtr.Zero)
89 return null;
90
91 try
92 {
93 return (CoreWebView2)Marshal.GetObjectForIUnknown(handle.CoreWebView2);
94 }
95 catch (Exception ex)
96 {
97 System.Diagnostics.Debug.WriteLine("Monaco CoreWebView2: " + ex.Message);
98 return null;
99 }
100 }
101
102 [SupportedOSPlatform("windows")]
103 private static CoreWebView2Controller? TryGetCoreWebView2Controller(IWindowsWebView2PlatformHandle handle)
104 {
105 if (handle.CoreWebView2Controller == IntPtr.Zero)
106 return null;
107
108 try
109 {
110 return (CoreWebView2Controller)Marshal.GetObjectForIUnknown(handle.CoreWebView2Controller);
111 }
112 catch (Exception ex)
113 {
114 System.Diagnostics.Debug.WriteLine("Monaco CoreWebView2Controller: " + ex.Message);
115 return null;
116 }
117 }
118}
119
View only · write via MCP/CIDE