feat:基础功能实现
feat: 重构 TodoList 架构,新增动态 API 与 MAUI 内嵌 Web 服务 feat:优化交互逻辑,优化发布流程
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
<maui:MauiWinUIApplication
|
||||
x:Class="TodoList.Maui.WinUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:maui="using:Microsoft.Maui"
|
||||
xmlns:local="using:TodoList.Maui.WinUI">
|
||||
|
||||
</maui:MauiWinUIApplication>
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace TodoList.Maui.WinUI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : MauiWinUIApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="C9D66914-AC5B-46D6-BE4B-214C893F6CB9" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>$placeholder$</DisplayName>
|
||||
<PublisherDisplayName>User Name</PublisherDisplayName>
|
||||
<Logo>$placeholder$.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="$placeholder$"
|
||||
Description="$placeholder$"
|
||||
Square150x150Logo="$placeholder$.png"
|
||||
Square44x44Logo="$placeholder$.png"
|
||||
BackgroundColor="transparent">
|
||||
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
|
||||
<uap:SplashScreen Image="$placeholder$.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<Capability Name="internetClient" />
|
||||
</Capabilities>
|
||||
|
||||
</Package>
|
||||
@@ -0,0 +1,129 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TodoList.Maui.Platforms.Windows
|
||||
{
|
||||
public class WindowsKeyboardHandler : IDisposable
|
||||
{
|
||||
private KeyboardHook _keyboardHook;
|
||||
private bool _isDisposed;
|
||||
|
||||
public event EventHandler? EscKeyPressed;
|
||||
|
||||
public WindowsKeyboardHandler()
|
||||
{
|
||||
_keyboardHook = new KeyboardHook();
|
||||
_keyboardHook.KeyPressed += OnKeyPressed;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_keyboardHook.Hook();
|
||||
}
|
||||
|
||||
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
||||
{
|
||||
if (e.Key == 0x1B && !e.IsKeyDown)
|
||||
{
|
||||
EscKeyPressed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_keyboardHook.Unhook();
|
||||
_keyboardHook.KeyPressed -= OnKeyPressed;
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KeyboardHook : IDisposable
|
||||
{
|
||||
private const int WH_KEYBOARD_LL = 13;
|
||||
private const int WM_KEYDOWN = 0x0100;
|
||||
private const int WM_KEYUP = 0x0101;
|
||||
private const int WM_SYSKEYDOWN = 0x0104;
|
||||
private const int WM_SYSKEYUP = 0x0105;
|
||||
|
||||
private IntPtr _hookID = IntPtr.Zero;
|
||||
private LowLevelKeyboardProc _proc;
|
||||
private bool _isDisposed;
|
||||
|
||||
public event EventHandler<KeyPressedEventArgs>? KeyPressed;
|
||||
|
||||
public KeyboardHook()
|
||||
{
|
||||
_proc = HookCallback;
|
||||
}
|
||||
|
||||
public void Hook()
|
||||
{
|
||||
_hookID = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle("user32"), 0);
|
||||
}
|
||||
|
||||
public void Unhook()
|
||||
{
|
||||
if (_hookID != IntPtr.Zero)
|
||||
{
|
||||
UnhookWindowsHookEx(_hookID);
|
||||
_hookID = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
int vkCode = Marshal.ReadInt32(lParam);
|
||||
bool isKeyDown = wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN;
|
||||
bool isKeyUp = wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP;
|
||||
|
||||
if (isKeyDown || isKeyUp)
|
||||
{
|
||||
var args = new KeyPressedEventArgs(vkCode, isKeyDown);
|
||||
KeyPressed?.Invoke(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(_hookID, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Unhook();
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
}
|
||||
|
||||
internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
internal class KeyPressedEventArgs : EventArgs
|
||||
{
|
||||
public int Key { get; }
|
||||
public bool IsKeyDown { get; }
|
||||
|
||||
public KeyPressedEventArgs(int key, bool isKeyDown)
|
||||
{
|
||||
Key = key;
|
||||
IsKeyDown = isKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#if WINDOWS
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.UI.Windowing;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace TodoList.Maui.Platforms.Windows
|
||||
{
|
||||
public class WindowsWindowService
|
||||
{
|
||||
private const int SW_HIDE = 0;
|
||||
private const int SW_SHOW = 5;
|
||||
private const int SW_RESTORE = 9;
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
public void HideWindow(Window window)
|
||||
{
|
||||
if (window == null) return;
|
||||
|
||||
var platformWindow = window.Handler?.PlatformView;
|
||||
if (platformWindow == null) return;
|
||||
|
||||
var nativeWindow = (Microsoft.UI.Xaml.Window)platformWindow;
|
||||
var hWnd = WindowNative.GetWindowHandle(nativeWindow);
|
||||
if (hWnd == IntPtr.Zero) return;
|
||||
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
}
|
||||
|
||||
public void RestoreWindow(Window window)
|
||||
{
|
||||
if (window == null) return;
|
||||
|
||||
var platformWindow = window.Handler?.PlatformView;
|
||||
if (platformWindow == null) return;
|
||||
|
||||
var nativeWindow = (Microsoft.UI.Xaml.Window)platformWindow;
|
||||
var hWnd = WindowNative.GetWindowHandle(nativeWindow);
|
||||
if (hWnd == IntPtr.Zero) return;
|
||||
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
ShowWindow(hWnd, SW_RESTORE);
|
||||
}
|
||||
|
||||
public void MinimizeWindow(Window window)
|
||||
{
|
||||
if (window == null) return;
|
||||
|
||||
var platformWindow = window.Handler?.PlatformView;
|
||||
if (platformWindow == null) return;
|
||||
|
||||
var nativeWindow = (Microsoft.UI.Xaml.Window)platformWindow;
|
||||
var appWindow = nativeWindow.AppWindow;
|
||||
|
||||
if (appWindow != null)
|
||||
{
|
||||
var overlappedPresenter = appWindow.Presenter as OverlappedPresenter;
|
||||
if (overlappedPresenter != null)
|
||||
{
|
||||
overlappedPresenter.Minimize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="TodoList.Maui.WinUI.app"/>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<!-- The combination of below two tags have the following effect:
|
||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
||||
2) System < Windows 10 Anniversary Update
|
||||
-->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
Reference in New Issue
Block a user