diff --git a/.github/workflows/dotnet-desktop.yml b/.github/workflows/dotnet-desktop.yml new file mode 100644 index 0000000..e718dd9 --- /dev/null +++ b/.github/workflows/dotnet-desktop.yml @@ -0,0 +1,115 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow will build, test, sign and package a WPF or Windows Forms desktop application +# built on .NET Core. +# To learn how to migrate your existing application to .NET Core, +# refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework +# +# To configure this workflow: +# +# 1. Configure environment variables +# GitHub sets default environment variables for every workflow run. +# Replace the variables relative to your project in the "env" section below. +# +# 2. Signing +# Generate a signing certificate in the Windows Application +# Packaging Project or add an existing signing certificate to the project. +# Next, use PowerShell to encode the .pfx file using Base64 encoding +# by running the following Powershell script to generate the output string: +# +# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte +# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' +# +# Open the output file, SigningCertificate_Encoded.txt, and copy the +# string inside. Then, add the string to the repo as a GitHub secret +# and name it "Base64_Encoded_Pfx." +# For more information on how to configure your signing certificate for +# this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing +# +# Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key". +# See "Build the Windows Application Packaging project" below to see how the secret is used. +# +# For more information on GitHub Actions, refer to https://github.com/features/actions +# For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications, +# refer to https://github.com/microsoft/github-actions-for-desktop-apps + +name: .NET Core Desktop + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + + build: + + strategy: + matrix: + configuration: [Debug, Release] + + runs-on: windows-latest # For a list of available runner types, refer to + # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on + + env: + Solution_Name: your-solution-name # Replace with your solution name, i.e. MyWpfApp.sln. + Test_Project_Path: your-test-project-path # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj. + Wap_Project_Directory: your-wap-project-directory-name # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package. + Wap_Project_Path: your-wap-project-path # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj. + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Install the .NET Core workload + - name: Install .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild + - name: Setup MSBuild.exe + uses: microsoft/setup-msbuild@v2 + + # Execute all unit tests in the solution + - name: Execute unit tests + run: dotnet test + + # Restore the application to populate the obj folder with RuntimeIdentifiers + - name: Restore the application + run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration + env: + Configuration: ${{ matrix.configuration }} + + # Decode the base 64 encoded pfx and save the Signing_Certificate + - name: Decode the pfx + run: | + $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") + $certificatePath = Join-Path -Path $env:Wap_Project_Directory -ChildPath GitHubActionsWorkflow.pfx + [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) + + # Create the app package by building and packaging the Windows Application Packaging project + - name: Create the app package + run: msbuild $env:Wap_Project_Path /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} + env: + Appx_Bundle: Always + Appx_Bundle_Platforms: x86|x64 + Appx_Package_Build_Mode: StoreUpload + Configuration: ${{ matrix.configuration }} + + # Remove the pfx + - name: Remove the pfx + run: Remove-Item -path $env:Wap_Project_Directory\GitHubActionsWorkflow.pfx + + # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact + - name: Upload build artifacts + uses: actions/upload-artifact@v3 + with: + name: MSIX Package + path: ${{ env.Wap_Project_Directory }}\AppPackages diff --git a/EyeGuard.sln b/EyeGuard.sln index d808435..bedae84 100644 --- a/EyeGuard.sln +++ b/EyeGuard.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31729.503 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EyeGuard", "EyeGuard\EyeGuard.csproj", "{9BA2871B-1F35-48CE-9316-9CEF99382BA2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|x86.ActiveCfg = Debug|x86 - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|x86.Build.0 = Debug|x86 - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|Any CPU.Build.0 = Release|Any CPU - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|x86.ActiveCfg = Release|x86 - {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A8A7FFE3-F4A5-4B72-B975-460C8C19B2EB} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34009.444 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EyeGuard", "EyeGuard\EyeGuard.csproj", "{9BA2871B-1F35-48CE-9316-9CEF99382BA2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|x86.ActiveCfg = Debug|x86 + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Debug|x86.Build.0 = Debug|x86 + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|Any CPU.Build.0 = Release|Any CPU + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|x86.ActiveCfg = Release|x86 + {9BA2871B-1F35-48CE-9316-9CEF99382BA2}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A8A7FFE3-F4A5-4B72-B975-460C8C19B2EB} + EndGlobalSection +EndGlobal diff --git a/EyeGuard/BLL/TopMostTool.cs b/EyeGuard/BLL/TopMostTool.cs index 0df9501..ac692e4 100644 --- a/EyeGuard/BLL/TopMostTool.cs +++ b/EyeGuard/BLL/TopMostTool.cs @@ -18,7 +18,19 @@ public class TopMostTool public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); //取消窗体置顶 public const uint SWP_NOMOVE = 0x0002; //不调整窗体位置 public const uint SWP_NOSIZE = 0x0001; //不调整窗体大小 - + public const uint SWP_NOACTIVATE = 0x0010; // do not grab focus of the current foreground window + public const int GWL_EXSTYLE = -20; + public const int WS_EX_TRANSPARENT = 0x00000020; + public const int WS_EX_LAYERED = 0x00080000; + public const int WS_EX_NOACTIVATE = 0x08000000; + public const int WS_EX_TOOLWINDOW = 0x00000080; + + // Declare the WinAPI functions + [DllImport("user32.dll")] + public static extern int GetWindowLong(IntPtr hwnd, int index); + + [DllImport("user32.dll")] + public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle); /// /// 是否显示最前 /// @@ -42,7 +54,13 @@ public class TopMostTool /// 需要置顶的窗体的IntPtr public static void setTop(IntPtr CustomBar) { - SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE); + SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE | TopMostTool.SWP_NOACTIVATE); + } + + public static void setClickThrough(IntPtr CustomBar) + { + int initialStyle = GetWindowLong(CustomBar, GWL_EXSTYLE); + SetWindowLong(CustomBar, GWL_EXSTYLE, initialStyle | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE); } @@ -60,7 +78,7 @@ public static void setTop(string Name,bool Sustain=true) { if (CustomBar != null) { - SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE); + SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE | TopMostTool.SWP_NOACTIVATE); return; } } @@ -72,7 +90,7 @@ public static void setTop(string Name,bool Sustain=true) Thread.Sleep(800); if (CustomBar != null) { - SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE); + SetWindowPos(CustomBar, TopMostTool.HWND_TOPMOST, 0, 0, 0, 0, TopMostTool.SWP_NOMOVE | TopMostTool.SWP_NOSIZE | TopMostTool.SWP_NOACTIVATE); } } Isop = false; diff --git a/EyeGuard/Dal.cs b/EyeGuard/Dal.cs index 33e45e2..8323ec0 100644 --- a/EyeGuard/Dal.cs +++ b/EyeGuard/Dal.cs @@ -42,6 +42,7 @@ public Model ReturnData() Model md = new Model(); //读取配置项中的配置 md.Work = Data["Work"]; + md.Voice = Data["Voice"] != 0; md.BreakPoints = Data["BreakPoints"]; md.LockMode = (Model.lock_mode)Data["LockMode"]; md.TimerMode = (Model.timer_mode)Data["TimerMode"]; @@ -69,6 +70,7 @@ public void SetData(Model md) Data["Unlock"] = md.Unlock; Data["IsIntelligent"] = md.IsIntelligent; Data["ShutdownMode"] = (int)md.Shutdown.ShutdownMode; + Data["Voice"] = md.Voice ? 1 : 0; Serialize(); } @@ -90,6 +92,7 @@ public void Deserialize() string Unlock = ConfigHelper.GetConfig("Unlock"); string IsIntelligent = ConfigHelper.GetConfig("IsIntelligent"); string ShutdownMode = ConfigHelper.GetConfig("ShutdownMode"); + string Voice = ConfigHelper.GetConfig("Voice"); Data.Add("Work", Convert.ToInt32(Work)); @@ -102,6 +105,7 @@ public void Deserialize() Data.Add("Unlock", Convert.ToInt32(Unlock)); Data.Add("IsIntelligent", Convert.ToInt32(IsIntelligent)); Data.Add("ShutdownMode", Convert.ToInt32(ShutdownMode)); + Data.Add("Voice", Convert.ToInt32(Voice)); } @@ -121,6 +125,7 @@ public void Serialize() ConfigHelper.SetConfig("Unlock", Data["Unlock"].ToString()); ConfigHelper.SetConfig("IsIntelligent", Data["IsIntelligent"].ToString()); ConfigHelper.SetConfig("ShutdownMode", Data["ShutdownMode"].ToString()); + ConfigHelper.SetConfig("Voice", Data["Voice"].ToString()); } } diff --git a/EyeGuard/EyeGuard.csproj b/EyeGuard/EyeGuard.csproj index eb9b136..8f7d367 100644 --- a/EyeGuard/EyeGuard.csproj +++ b/EyeGuard/EyeGuard.csproj @@ -2,7 +2,7 @@ WinExe - net8.0-windows7.0 + net7.0-windows true favicon.ico AnyCPU;x86 diff --git a/EyeGuard/EyeGuard.xaml.cs b/EyeGuard/EyeGuard.xaml.cs index c002ecb..9e9bcbc 100644 --- a/EyeGuard/EyeGuard.xaml.cs +++ b/EyeGuard/EyeGuard.xaml.cs @@ -517,7 +517,10 @@ private void timer_Tick(object sender, EventArgs e) { if (Convert.ToInt32(time[0]) == 23 && Convert.ToInt32(time[1]) == 59 && Convert.ToInt32(time[2]) == 3) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + } Tips.Show("当前时间为:" + DateTime.Now.ToLongTimeString().ToString() + " 距离关机还有1分钟,请您注意保存好数据信息~"); } } @@ -525,7 +528,10 @@ private void timer_Tick(object sender, EventArgs e) { if (Convert.ToInt32(time[0]) == (md.Shutdown.Time - 1) && Convert.ToInt32(time[1]) == 59 && Convert.ToInt32(time[2]) == 3) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + } Tips.Show("当前时间为:" + DateTime.Now.ToLongTimeString().ToString() + " 距离关机还有1分钟,请您注意保存好数据信息~"); } } @@ -535,7 +541,10 @@ private void timer_Tick(object sender, EventArgs e) //到达关机时间 if (Convert.ToInt32(time[0]) == md.Shutdown.Time && Convert.ToInt32(time[1]) == (md.Shutdown.Branch - 1) && Convert.ToInt32(time[2]) == 3) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeShutdown.mp3").Play(); + } Tips.Show("当前时间为:" + DateTime.Now.ToLongTimeString().ToString() + " 距离关机还有1分钟,请您注意保存好数据信息~"); } } @@ -571,7 +580,10 @@ private void timer_Tick(object sender, EventArgs e) //休息前的提醒 游戏模式下不进行提醒 if ((md.Work - 1) * 60 == Count) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeRest.mp3").Play(); + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\BeforeRest.mp3").Play(); + } if (((int)md.TimerMode == 1 && bll.FullScreen())|| (int)md.TimerMode == 2) { return; @@ -582,8 +594,10 @@ private void timer_Tick(object sender, EventArgs e) //到达休息时间 if (md.Work * 60 == Count) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\Resting.mp3").Play(); - + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\Resting.mp3").Play(); + } switch (md.LockMode) { case lock_mode.透明模式: @@ -655,7 +669,10 @@ int dwExtraInfo //这里是整数类型 一般情况下设成为 0 /// private void Window_Loaded(object sender, RoutedEventArgs e) { - new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\Firing.mp3").Play(); + if (md.Voice) + { + new BLL.MP3Help($@"{AppDomain.CurrentDomain.BaseDirectory}Resources\MP3\Firing.mp3").Play(); + } md = bll.Initialization(); if (md.Display == 0) { diff --git a/EyeGuard/Model.cs b/EyeGuard/Model.cs index e31405c..01ca2df 100644 --- a/EyeGuard/Model.cs +++ b/EyeGuard/Model.cs @@ -8,6 +8,11 @@ public class Model /// public int Work { set; get; } + /// + /// enable /disable voice notice + /// + public bool Voice { set; get; } + /// /// 已经工作时间 /// diff --git a/EyeGuard/UI/LockScreen.xaml b/EyeGuard/UI/LockScreen.xaml index 795aa06..b2190ae 100644 --- a/EyeGuard/UI/LockScreen.xaml +++ b/EyeGuard/UI/LockScreen.xaml @@ -117,7 +117,7 @@ Margin="0,0,0,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" - FontSize="40" + FontSize="40" FontFamily="Microsoft YaHei UI Light" > diff --git a/EyeGuard/UI/SetUp.xaml b/EyeGuard/UI/SetUp.xaml index 62db491..6829f3d 100644 --- a/EyeGuard/UI/SetUp.xaml +++ b/EyeGuard/UI/SetUp.xaml @@ -9,7 +9,7 @@ xmlns:local="clr-namespace:EyeGuard.UI" Title="SetUp" Width="245" - Height="349.63" + Height="364" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Loaded="MetroWindow_Loaded" @@ -20,7 +20,7 @@ - + diff --git a/EyeGuard/UI/Tips.xaml.cs b/EyeGuard/UI/Tips.xaml.cs index cd0bb14..e9c7e95 100644 --- a/EyeGuard/UI/Tips.xaml.cs +++ b/EyeGuard/UI/Tips.xaml.cs @@ -3,6 +3,7 @@ using System.Windows; using System.Windows.Interop; using System.Windows.Threading; +using System.Runtime.InteropServices; namespace EyeGuard.UI { @@ -20,6 +21,9 @@ public static void Show(string value) if (Tips.Function == false) { Tips tp = new Tips(value); + tp.ShowActivated = false; + tp.Focusable = false; + tp.ShowInTaskbar = false; tp.Show(); } } @@ -101,7 +105,10 @@ private void timer1_Tick(object sender, EventArgs e) private void Window_Loaded(object sender, RoutedEventArgs e) { Console.WriteLine("提示窗口已经正确运行……"); - BLL.TopMostTool.setTop(this.Title); + IntPtr hwnd = new WindowInteropHelper(this).Handle; + BLL.TopMostTool.setClickThrough(hwnd); + BLL.TopMostTool.setTop(hwnd); + this.ShowActivated = false; } } }