Compare commits

..

102 Commits

Author SHA1 Message Date
DESKTOP-3BO4HSG\ksat f265b48e8a chore: optimized singleton pattern is lazy and thread-safe
2 years ago
DESKTOP-3BO4HSG\ksat 758a21f9ad perf: update new serve
2 years ago
Song 0b3a9ee6f0
feat: update config model
2 years ago
DESKTOP-3BO4HSG\ksat ec2ded168e perf: optimize animation effects
2 years ago
DESKTOP-3BO4HSG\ksat 98b6408115 docs: api failure description
2 years ago
DESKTOP-3BO4HSG\ksat 67141f97bd docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 5b9731caec perf: update version to 0.25
2 years ago
SONGE9B3\song_pd_win11 d5eac2ebf0 perf: optimized display
2 years ago
SONGE9B3\song_pd_win11 7eaa02503c feat: add toast
2 years ago
Song 0bdd7757ce
docs: update readme
2 years ago
SONGE9B3\song_pd_win11 4000bd23d5 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 46b1da8b14 Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
SONGE9B3\song_pd_win11 af38ef7cfb chore: update version tag
2 years ago
Song 18ecb6aca5
Update README.md
2 years ago
SONGE9B3\song_pd_win11 8abd2f3dea feat: update new api
2 years ago
DESKTOP-3BO4HSG\ksat 21c5cab0f8 feat: add tooltip
2 years ago
DESKTOP-3BO4HSG\ksat 9b2fbc6e49 perf: create desktop shorcut at first time
2 years ago
DESKTOP-3BO4HSG\ksat 01b9af34dd Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
DESKTOP-3BO4HSG\ksat e4c690f226 feat: optimize the problem of blurred icons when switching resolution
2 years ago
zggsong d3da657e52 chore: ignore .dsstore
2 years ago
zggsong 127c5c3d56 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 1f6b277c8e Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
DESKTOP-3BO4HSG\ksat 1d91ab510e 0.21
2 years ago
DESKTOP-3BO4HSG\ksat b561f44678 feat: add reset hot keys
2 years ago
DESKTOP-3BO4HSG\ksat 471cc632b2 feat: add change hotkeys func
2 years ago
DESKTOP-3BO4HSG\ksat 84ea248601 perf: add keydown to textbox
2 years ago
DESKTOP-3BO4HSG\ksat 74eb8755a5 fix: hot keys conflict message
2 years ago
Song 0de7a3776d
docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 5fbfc19ec3 feat: add translation local cache function
2 years ago
DESKTOP-3BO4HSG\ksat a93c422838 perf: update chinese and english automatic recognition proportion configuration item
2 years ago
DESKTOP-3BO4HSG\ksat 4974e53bf1 Merge branch 'dev_settings'
2 years ago
DESKTOP-3BO4HSG\ksat d9d8d71fa7 perf: update translate while change api
2 years ago
DESKTOP-3BO4HSG\ksat 1a7e9599f5 chore: update click event
2 years ago
DESKTOP-3BO4HSG\ksat dcd47be44a perf: update setting
2 years ago
DESKTOP-3BO4HSG\ksat 655335d49f tmp
2 years ago
zggsong 1753630c90 docs: update readme for .net env
2 years ago
DESKTOP-3BO4HSG\ksat 999ed5c459 chore: add setting view
2 years ago
DESKTOP-3BO4HSG\ksat 41422a0f83 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 03e9652ad6 publish: 0.18
2 years ago
DESKTOP-3BO4HSG\ksat 4db74c1a66 chore(tray): add shortcut text
2 years ago
DESKTOP-3BO4HSG\ksat a91965a75d perf: adding manual gc ensures a very small memory footprint
2 years ago
DESKTOP-3BO4HSG\ksat c0643c40e9 feat: add updater by https://github.com/Planshit/Tai
2 years ago
DESKTOP-3BO4HSG\ksat 96fe851fbe perf: update combobox style
2 years ago
DESKTOP-3BO4HSG\ksat 11385128bc perf: optimize dark mode theme style
2 years ago
DESKTOP-3BO4HSG\ksat 6429342193 publish: 0.16
2 years ago
DESKTOP-3BO4HSG\ksat c7d7b984a0 fix: esc bind no control
2 years ago
SONGE9B3\song_pd_win11 579d967003 perf: replace hardcodet by forms notifyicon(win11 will have a better experience)
2 years ago
DESKTOP-3BO4HSG\ksat 741d9a2efd fix: topmost shortcut
2 years ago
SONGE9B3\song_pd_win11 3c3949fe07 chore: update close view when close
2 years ago
DESKTOP-3BO4HSG\ksat ca3d75a4fc chore: update tray and readme
2 years ago
DESKTOP-3BO4HSG\ksat 0923ccf415 fix: null input
2 years ago
DESKTOP-3BO4HSG\ksat b08b5de6ff chore: update view codes in vm
2 years ago
DESKTOP-3BO4HSG\ksat 5c76a1df83 chore: remove topmost view int viewmodel
2 years ago
DESKTOP-3BO4HSG\ksat 1ac7c152e2 feat: add screenshot translate
2 years ago
DESKTOP-3BO4HSG\ksat feef0e3d8b remove chi_sim
2 years ago
DESKTOP-3BO4HSG\ksat dcaa07680e add local ocr
2 years ago
DESKTOP-3BO4HSG\ksat 2afd51c783 feat: add screenshot to image
2 years ago
DESKTOP-3BO4HSG\ksat 1f1ecb1af6 tmp
2 years ago
DESKTOP-3BO4HSG\ksat ec121dbb58 perf: update view viewmodel split
2 years ago
DESKTOP-3BO4HSG\ksat 7a4aa1deb6 chore: add screen shot hot key and update exit codes
2 years ago
SONGE9B3\song_pd_win11 c8f71ad499 fix: array indexing problem
2 years ago
DESKTOP-3BO4HSG\ksat 1b54ee74c5 update 0.14
2 years ago
DESKTOP-3BO4HSG\ksat 8ed950259f remove loading
2 years ago
DESKTOP-3BO4HSG\ksat c07ad305f5 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 04fcde2b0f feat: add loading
2 years ago
DESKTOP-3BO4HSG\ksat c020e31e30 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 06a30fcad5 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 4985f5f47e tmp
2 years ago
DESKTOP-3BO4HSG\ksat f61f77154e tmp
2 years ago
SONGE9B3\song_pd_win11 e5440275c2 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 89d6a03df6 feat: View viewmodel separation
2 years ago
DESKTOP-3BO4HSG\ksat faa13358fd tmp
2 years ago
DESKTOP-3BO4HSG\ksat 1740c9b6fa tmp
2 years ago
DESKTOP-3BO4HSG\ksat f3992b2f19 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 7c8363b531 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 60cc864fa8 tmp
2 years ago
DESKTOP-3BO4HSG\ksat b8c28da3d6 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 980d3e36b8 tmp
2 years ago
DESKTOP-3BO4HSG\ksat cbcee3eb0a Merge branch 'main' into dev_split_view_vm
2 years ago
DESKTOP-3BO4HSG\ksat 3bef17be14 Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
DESKTOP-3BO4HSG\ksat ec7f7185b1 perf: update translate with lang switched
2 years ago
SONGE9B3\song_pd_win11 6c80d50740 chore: update readme
2 years ago
Song 25daf50c7d
docs: update readme
2 years ago
Song 3ff1ee8816
docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat d0080c56e7 perf(speech): Optimize speech synthesis cancellation after exiting the foreground
2 years ago
DESKTOP-3BO4HSG\ksat dd84d176f9 feat(speech): Add text-to-speech function
2 years ago
DESKTOP-3BO4HSG\ksat 7eb659266c chore(publish): update version info to 0.13
2 years ago
Song c53739102b
Update README.md
2 years ago
DESKTOP-3BO4HSG\ksat 7e0a30b8e8 tmp
2 years ago
DESKTOP-3BO4HSG\ksat de3e6f0db5 feat: 提取注册快捷键回调
2 years ago
DESKTOP-3BO4HSG\ksat 9708ff1cdd perf: update readme
2 years ago
SONGE9B3\song_pd_win11 8a56d109fd perf: add theme re/wr with config
2 years ago
SONGE9B3\song_pd_win11 a6d9a6ae09 perf: add write config
2 years ago
SONGE9B3\song_pd_win11 aab8f0d387 perf: update the selected service in the configuration file
2 years ago
SONGE9B3\song_pd_win11 83235deda4 tmp
2 years ago
SONGE9B3\song_pd_win11 492ef81f7c perf: extraction of public methods
2 years ago
DESKTOP-3BO4HSG\ksat bef40870b7 perf: update border ui color
2 years ago
DESKTOP-3BO4HSG\ksat fbc7295fff perf: update ui border in glittering color
2 years ago
DESKTOP-3BO4HSG\ksat 65ba0ede29 tmp
2 years ago
DESKTOP-3BO4HSG\ksat 6fb8c29dfd perf: version
2 years ago
DESKTOP-3BO4HSG\ksat 94c67089e7 perf: update notifyicon
2 years ago
DESKTOP-3BO4HSG\ksat 4eaadff93b fix: esc to unset topmost
2 years ago

4
.gitignore vendored

@ -2,6 +2,8 @@
bin/
obj/
*.user
.idea/
packages/
packages/
.DS_Store

@ -4,9 +4,18 @@
</a>
</p>
<p align="center">
<a href="https://github.com/ZGGSONG/STranslate/blob/main/LICENSE" target="_self">
<img alt="Latest GitHub release" src="https://img.shields.io/github/license/ZGGSONG/STranslate" />
</a>
<a href="https://github.com/ZGGSONG/STranslate/releases/latest" target="_blank">
<img alt="Latest GitHub release" src="https://img.shields.io/github/release/ZGGSONG/STranslate.svg" />
</a>
<a href="https://hub.docker.com/r/zggsong/translate">
<img alt="Docker pull" src="https://img.shields.io/docker/pulls/zggsong/translate">
</a>
<a href="https://github.com/ZGGSONG/STranslate" target="_self">
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/ZGGSONG/STranslate" />
</a>
</p>
<h1 align="center">STranslate</h1>
@ -16,15 +25,20 @@
## 功能
- [x] 添加 DeepL API
- [x] 实现基本翻译功能
- [x] 优化防止多开
- [x] 添加划词翻译
- [x] 添加复制结果蛇形、大小驼峰
- [x] 软件层面识别语种(目前支持中英文)
- [x] 软件层面识别语种(中英文)
- [x] 添加开机自启
- [x] 添加亮/暗主题
- [ ] 添加 OCR 翻译
- [ ] 添加翻译记录缓存功能
- [x] 添加明/暗主题
- [x] 添加 UI 设置缓存(用户目录下 `AppData\Local\STranslate`)
- [x] 添加离线语音合成
- [x] 添加离线截图文字识别(支持英文, 中文数据包过大且体验不好)
- [x] 添加检查更新
- [x] 添加翻译记录缓存功能
## 安装
下载最新 [Release](https://github.com/ZGGSONG/STranslate/releases) 版本后解压即可使用
## 使用
@ -33,28 +47,92 @@
![previews_dark](./example_dark.png)
打开软件后会静默在后台,等待调用
1. 全局监听快捷键
- `Alt` + `A` 打开软件界面,输入内容按回车翻译
- `Alt` + `D` 复制当前鼠标选中内容并翻译
- `Alt` + `S` 截图选中区域内容并翻译
- `Alt` + `G` 打开窗口(不清空内容)
2. 软件内快捷键
1. 软件内快捷键
- `ESC` 隐藏界面
- `Ctrl+Shift+Q` 退出程序
- `Ctrl+Shift+R` 切换主题
- `Ctrl+Shift+T` 置顶/取消置顶
点击软件外部界面任意处或点击软件则会自动隐藏到后台,即用即走。
点击软件外部任意处即自动隐藏到后台——即用即走。
> STranslate依赖于.NET Framework 4.8 运行环境如果程序启动时提示“This application requires *** .NETFramework,Version=v4.8”,请点击以下链接下载并安装.NET Framework 4.8 运行环境。
> [适用于 Windows 的 Microsoft .NET Framework 4.8 脱机安装程序下载](https://download.visualstudio.microsoft.com/download/pr/2d6bb6b2-226a-4baa-bdec-798822606ff1/8494001c276a4b96804cde7829c04d7f/ndp48-x86-x64-allos-enu.exe) | [Microsoft Support](https://support.microsoft.com/zh-cn/topic/%E9%80%82%E7%94%A8%E4%BA%8E-windows-%E7%9A%84-microsoft-net-framework-4-8-%E8%84%B1%E6%9C%BA%E5%AE%89%E8%A3%85%E7%A8%8B%E5%BA%8F-9d23f658-3b97-68ab-d013-aa3c3e7495e0)
## 卸载
1. 删除软件运行目录
2. 打开 cmd 运行下面的命令即可
```shell
rd /s /q "%localappdata%\stranslate"
```
## 开发历史
- 2023-03-02 0.25 添加复制提醒动画
- 2023-02-28 0.24 添加 deepl([deno.dev](deno.dev)) 接口(已经安装的cmd运行 `del %localappdata%\stranslate\stranslate.json` 后打开即可更新接口)
- 2023-02-24 0.22 优化分辨率切换时托盘图标模糊问题
- 2023-01-17 0.20 添加翻译记录缓存功能,重复翻译从本地数据库获取,本地记录数量上限可调整
- 2023-01-12 0.18 优化 GC 后台静默运行内存占用保持 4MB 左右
- 2023-01-12 0.17 添加检查更新功能
- 2023-01-10 0.15 添加离线 OCR 功能,其使用 [tesseract](https://github.com/tesseract-ocr/tesseract) 目前仅支持英文
<details>
<summary>自修改提示</summary>
有经验者可自行下载 [语言包](https://github.com/tesseract-ocr/tessdata) 至 `tessdata` 目录后修改 `Util`中`TesseractGetText`方法即可
```C#
public static string TesseractGetText(Bitmap bmp)
{
try
{
using (var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default))
//using (var engine = new TesseractEngine(@"./tessdata", "chi_sim", EngineMode.Default))
{
using(var pix = PixConverter.ToPix(bmp))
{
using (var page = engine.Process(pix))
{
return page.GetText();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
```
</details>
3. 0.08 版本添加开机启动
- 2023-12-28 0.10 添加明暗主题切换功能
![previews](./example_tray.png)
- 2022-12-27 0.08 版本添加开机启动
## 接口失效
## 如果接口失效
若远端接口均失效,需要自己本地运行翻译服务(感谢[zu1k](https://github.com/zu1k)),根据自己的系统 [下载](https://github.com/zu1k/removed-2022-07-12) 自己的版本,软件右上角选择 `local` 接口即可
当请求人数较多时,远端接口可能暂时失效,可自行运行翻译接口程序
1. **【推荐】** 下载对应平台可 [执行文件](https://github.com/ZGGSONG/STranslate/releases/tag/0.01),随后在软件右上角选择 `local` 接口即可
2. 【进阶】 下载 [docker镜像](https://hub.docker.com/r/zggsong/translate),关闭软件 - cmd 运行 `start %localappdata%\stranslate\stranslate.json` - 修改接口地址 - 重启软件即可
## 参考项目
[https://github.com/NPCDW/WpfTool](https://github.com/NPCDW/WpfTool)
[https://github.com/zu1k/removed-2022-07-12/releases/tag/0.1.2](https://github.com/zu1k/removed-2022-07-12/releases/tag/0.1.2)
[https://github.com/Planshit/Tai](https://github.com/Planshit/Tai)

@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STranslate", "STranslate\STranslate.csproj", "{2597B480-185C-4D6D-94EC-8641BB6777F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Updater\Updater.csproj", "{A49C9514-81CA-4FB6-A586-17477E4F28A8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.Build.0 = Release|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -1,7 +1,7 @@
<Application x:Class="STranslate.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
StartupUri="View/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

@ -18,6 +18,8 @@ namespace STranslate
if (mutex.WaitOne(0, false))
{
base.OnStartup(e);
Util.Util.FlushMemory();
}
else
{

@ -0,0 +1,2 @@
@echo off
rd /s /q "%localappdata%\stranslate"

@ -0,0 +1,58 @@
using Newtonsoft.Json;
using STranslate.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Helper
{
public class ConfigHelper : Singleton<ConfigHelper>
{
public T ReadConfig<T>()
{
try
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(_CnfName));
}
catch (Exception)
{
throw new Exception("读取配置错误,请检查配置文件");
}
}
public void WriteConfig(object obj)
{
File.WriteAllText(_CnfName, JsonConvert.SerializeObject(obj, Formatting.Indented));
}
public ConfigHelper()
{
if (!Directory.Exists(_ApplicationData))//判断是否存在
{
Directory.CreateDirectory(_ApplicationData);//创建新路径
ShortcutHelper.SetDesktopShortcut();//创建桌面快捷方式
}
if (!File.Exists(_CnfName))//文件不存在
{
FileStream fs1 = new FileStream(_CnfName, FileMode.Create, FileAccess.ReadWrite);
fs1.Close();
WriteConfig(new ConfigModel().InitialConfig());
}
}
/// <summary>
/// 配置文件
/// </summary>
private static string _CnfName => $"{_ApplicationData}\\{_AppName.ToLower()}.json";
/// <summary>
/// C:\Users\user\AppData\Local\STranslate
/// </summary>
private static string _ApplicationData => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\{_AppName}";
private static readonly string _AppName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
}
}

@ -9,7 +9,8 @@ namespace STranslate.Helper
public static String Get()
{
SendCtrlC();
Thread.Sleep(200);
System.Diagnostics.Debug.Print(STranslate.ViewModel.SettingsVM.Instance.WordPickupInterval.ToString());
Thread.Sleep((int)STranslate.ViewModel.SettingsVM.Instance.WordPickupInterval);
return NativeMethodHelper.GetText();
}

@ -1,43 +1,12 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Interop;
using WpfScreenHelper;
using static STranslate.Helper.NativeMethodHelper;
namespace STranslate.Helper
{
public static class Hotkeys
{
public static class InputTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 65;
public static String Text = "A";
public static bool Conflict = false;
}
public static class CrosswordTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 68;
public static String Text = "D";
public static bool Conflict = false;
}
#if false
public static class ScreenShotTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 83;
public static String Text = "S";
public static bool Conflict = false;
}
#endif
public static class OpenMainWindow
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 71;
public static String Text = "G";
public static bool Conflict = false;
}
}
internal class HotkeysHelper
{
@ -49,7 +18,7 @@ namespace STranslate.Helper
public static int CrosswordTranslateId = 855;
public static byte CrosswordTranslateModifiers;
public static int CrosswordTranslateKey;
#if false
#if true
public static int ScreenShotTranslateId = 856;
public static byte ScreenShotTranslateModifiers;
public static int ScreenShotTranslateKey;
@ -58,39 +27,90 @@ namespace STranslate.Helper
public static byte OpenMainWindowModifiers;
public static int OpenMainWindowKey;
public delegate void HotKeyCallBackHanlder();
private static Dictionary<int, HotKeyCallBackHanlder> keymap = new Dictionary<int, HotKeyCallBackHanlder>();
public static void InitialHook(Window window)
{
var hwnd = new WindowInteropHelper(window).Handle;
RegisterHotKey(hwnd);
var _hwndSource = HwndSource.FromHwnd(hwnd);
_hwndSource.AddHook(WndProc);
}
/// <summary>
/// 注册快捷键
/// https://git2.nas.zggsong.cn:5001/zggsong/STranslate/src/commit/2fe17e7f6596b47b33a40d8733a0527ba5d9b2fb/STranslate/Utils/HotKeysUtil.cs
/// </summary>
/// <param name="id">InputTranslateId、ScreenShotTranslateId、CrosswordTranslateId、OpenMainWindowId</param>
/// <param name="callBack"></param>
public static void Register(int id, HotKeyCallBackHanlder callBack)
{
keymap[id] = callBack;
}
/// <summary>
/// 屏幕分辨率以及文本显示比例变更对应的消息标志
/// </summary>
private const int WmDisplayChange = 0x007e;
/// <summary>
/// 文本显示比例变更消息标志
/// </summary>
private const int WmTextChange = 0x02E0;
/// <summary>
/// window消息定义的 注册的热键消息标志
/// </summary>
private const int WmHotkeys = 0x0312;
/// <summary>
/// 快捷键消息处理
/// </summary>
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WmHotkeys:
int id = wParam.ToInt32();
if (keymap.TryGetValue(id, out var callback))
{
callback();
}
break;
}
return IntPtr.Zero;
}
/// <summary>
/// 注册快捷键
/// </summary>
/// <param name="mainFormHandle"></param>
public static void RegisterHotKey(IntPtr mainFormHandle)
private static void RegisterHotKey(IntPtr mainFormHandle)
{
HotkeysHelper.mainFormHandle = mainFormHandle;
InputTranslateModifiers = Hotkeys.InputTranslate.Modifiers;
InputTranslateKey = Hotkeys.InputTranslate.Key;
CrosswordTranslateModifiers = Hotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = Hotkeys.CrosswordTranslate.Key;
InputTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers;
InputTranslateKey = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key;
CrosswordTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key;
#if false
ScreenShotTranslateModifiers = Hotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = Hotkeys.ScreenShotTranslate.Key;
if (Hotkeys.ScreenShotTranslate.Key != 0)
#if true
ScreenShotTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key;
if (ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key != 0)
{
Hotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, Hotkeys.ScreenShotTranslate.Modifiers, Hotkeys.ScreenShotTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key);
}
#endif
if (Hotkeys.InputTranslate.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key != 0)
{
Hotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, Hotkeys.InputTranslate.Modifiers, Hotkeys.InputTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key);
}
if (Hotkeys.CrosswordTranslate.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key != 0)
{
Hotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, Hotkeys.CrosswordTranslate.Modifiers, Hotkeys.CrosswordTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key);
}
if (Hotkeys.OpenMainWindow.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key != 0)
{
Hotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, Hotkeys.OpenMainWindow.Modifiers, Hotkeys.OpenMainWindow.Key);
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key);
}
}
@ -101,7 +121,7 @@ namespace STranslate.Helper
{
UnregisterHotKey(mainFormHandle, InputTranslateId);
UnregisterHotKey(mainFormHandle, CrosswordTranslateId);
#if false
#if true
UnregisterHotKey(mainFormHandle, ScreenShotTranslateId);
#endif
UnregisterHotKey(mainFormHandle, OpenMainWindowId);
@ -112,59 +132,59 @@ namespace STranslate.Helper
/// </summary>
public static void ReRegisterHotKey()
{
if (Hotkeys.InputTranslate.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, InputTranslateId);
}
else if (InputTranslateModifiers != Hotkeys.InputTranslate.Modifiers || InputTranslateKey != Hotkeys.InputTranslate.Key)
else if (InputTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers || InputTranslateKey != ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key)
{
{
UnregisterHotKey(mainFormHandle, InputTranslateId);
Hotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, Hotkeys.InputTranslate.Modifiers, Hotkeys.InputTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key);
}
}
InputTranslateModifiers = Hotkeys.InputTranslate.Modifiers;
InputTranslateKey = Hotkeys.InputTranslate.Key;
InputTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers;
InputTranslateKey = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key;
if (Hotkeys.CrosswordTranslate.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, CrosswordTranslateId);
}
else if (CrosswordTranslateModifiers != Hotkeys.CrosswordTranslate.Modifiers || CrosswordTranslateKey != Hotkeys.CrosswordTranslate.Key)
else if (CrosswordTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers || CrosswordTranslateKey != ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key)
{
{
UnregisterHotKey(mainFormHandle, CrosswordTranslateId);
Hotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, Hotkeys.CrosswordTranslate.Modifiers, Hotkeys.CrosswordTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key);
}
}
CrosswordTranslateModifiers = Hotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = Hotkeys.CrosswordTranslate.Key;
CrosswordTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key;
#if false
if (Hotkeys.ScreenShotTranslate.Key == 0)
#if true
if (ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, ScreenShotTranslateId);
}
else if (ScreenShotTranslateModifiers != Hotkeys.ScreenShotTranslate.Modifiers || ScreenShotTranslateKey != Hotkeys.ScreenShotTranslate.Key)
else if (ScreenShotTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers || ScreenShotTranslateKey != ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key)
{
UnregisterHotKey(mainFormHandle, ScreenShotTranslateId);
Hotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, Hotkeys.ScreenShotTranslate.Modifiers, Hotkeys.ScreenShotTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key);
}
ScreenShotTranslateModifiers = Hotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = Hotkeys.ScreenShotTranslate.Key;
ScreenShotTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key;
#endif
if (Hotkeys.OpenMainWindow.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key == 0)
{
UnregisterHotKey(mainFormHandle, OpenMainWindowId);
}
else if (OpenMainWindowModifiers != Hotkeys.OpenMainWindow.Modifiers || OpenMainWindowKey != Hotkeys.OpenMainWindow.Key)
else if (OpenMainWindowModifiers != ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers || OpenMainWindowKey != ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key)
{
UnregisterHotKey(mainFormHandle, OpenMainWindowId);
Hotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, Hotkeys.OpenMainWindow.Modifiers, Hotkeys.OpenMainWindow.Key);
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key);
}
OpenMainWindowModifiers = Hotkeys.OpenMainWindow.Modifiers;
OpenMainWindowKey = Hotkeys.OpenMainWindow.Key;
OpenMainWindowModifiers = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers;
OpenMainWindowKey = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key;
}
}
}

@ -5,6 +5,18 @@ using System.Runtime.CompilerServices;
namespace STranslate.Helper
{
/// <summary>
/// Generate Singleton
/// </summary>
/// <typeparam name="T"></typeparam>
public class Singleton<T> where T : class
{
private static readonly Lazy<T> _instance = new Lazy<T>(()
=> Activator.CreateInstance(typeof(T), true) as T, true);
public static T Instance => _instance.Value;
}
/// <summary>
/// 通知
/// </summary>

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Helper
{
public class ProcessHelper
{
public static bool Run(string filename, string[] args)
{
try
{
string arguments = "";
foreach (string arg in args)
{
arguments += $"\"{arg}\" ";
}
arguments = arguments.Trim();
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(filename, arguments);
process.StartInfo = startInfo;
process.Start();
return true;
}
catch (Exception)
{
//Logger.Error(ex.ToString());
return false;
}
}
}
}

@ -6,7 +6,7 @@ using IWshRuntimeLibrary;
namespace STranslate.Helper
{
public class StartupHelper
public class ShortcutHelper
{
#region public method
@ -32,6 +32,13 @@ namespace STranslate.Helper
{
ShortCutDelete(appPath, StartUpPath);
}
/// <summary>
/// 设置桌面快捷方式
/// </summary>
public static void SetDesktopShortcut()
{
ShortCutCreate(true);
}
#endregion
#region params
@ -40,6 +47,11 @@ namespace STranslate.Helper
/// </summary>
private static readonly string StartUpPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
/// <summary>
/// 用户桌面目录
/// </summary>
private static readonly string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
/// <summary>
/// 当前程序二进制文件路径
/// </summary>
@ -49,6 +61,8 @@ namespace STranslate.Helper
/// 组合的开机启动目录中的快捷方式路径
/// </summary>
private static readonly string appShortcutPath = Path.Combine(StartUpPath, Path.GetFileNameWithoutExtension(appPath) + ".lnk");
private static readonly string desktopShortcutPath = Path.Combine(DesktopPath, Path.GetFileNameWithoutExtension(appPath) + ".lnk");
#endregion
#region native method
@ -136,18 +150,25 @@ namespace STranslate.Helper
return Result;
}
/// <summary>
/// 为本程序创建一个开机启动快捷方式
/// 为本程序创建一个快捷方式
/// </summary>
private static bool ShortCutCreate()
/// <param name="isDesktop">是否为桌面快捷方式</param>
/// <returns></returns>
private static bool ShortCutCreate(bool isDesktop = false)
{
bool Result = false;
try
{
ShortCutDelete(appPath, StartUpPath);
if (!isDesktop)
ShortCutDelete(appPath, StartUpPath);
var shellType = Type.GetTypeFromProgID("WScript.Shell");
dynamic shell = Activator.CreateInstance(shellType);
var shortcut = shell.CreateShortcut(appShortcutPath);
IWshShortcut shortcut;
if (!isDesktop)
shortcut = shell.CreateShortcut(appShortcutPath);
else
shortcut = shell.CreateShortcut(desktopShortcutPath);
shortcut.TargetPath = Assembly.GetEntryAssembly().Location;
shortcut.Arguments = string.Empty;
shortcut.WorkingDirectory = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

@ -0,0 +1,98 @@
using SQLite;
using STranslate.Model;
using STranslate.ViewModel;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace STranslate.Helper
{
//https://github.com/praeclarum/sqlite-net
public class SqliteHelper : IDisposable
{
public SqliteHelper()
{
_sqlDB = new SQLiteConnection(_dbName);
_sqlDB.CreateTable<SqliteModel>();
}
public void Insert(DateTime time, string source, string target, LanguageEnum sourceLang, LanguageEnum targetLang, string api)
{
try
{
var model = new SqliteModel
{
Time = time,
SourceText = source,
TargetText = target,
SourceLang = sourceLang.ToString(),
TargetLang = targetLang.ToString(),
Api = api,
};
//查询最大数量
var count = _sqlDB.Table<SqliteModel>().Count();
if (count >= SettingsVM.Instance.MaxHistoryCount)
{
_sqlDB.Execute("delete from histories where id in (select id from histories limit (?))"
, count + 1 - SettingsVM.Instance.MaxHistoryCount);
}
//手动切换目标语言强制插入替换
_sqlDB.Table<SqliteModel>()
.Where(x => x.SourceText.Equals(model.SourceText))
.ToList().ForEach(x =>
{
_sqlDB.Delete(x);
});
_sqlDB.Insert(model);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"本地记录插入错误\n{ex.Message}");
}
}
/// <summary>
/// 查询记录
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string Query(string str)
{
var query = _sqlDB.Table<SqliteModel>().Where(x => x.SourceText.Equals(str));
if (query.Count() <= 0)
{
return string.Empty;
}
else//如果超过一个删除多余的
{
var tmp = query.ToList();
for (int i = 1; i < tmp.Count; i++)
{
_sqlDB.Delete(tmp[i]);
}
return query.First().TargetText;
}
}
public void Dispose()
{
_sqlDB.Close();
}
private readonly SQLiteConnection _sqlDB;
/// <summary>
/// 数据文件
/// </summary>
private static string _dbName => $"{_ApplicationData}\\{_AppName.ToLower()}.db";
/// <summary>
/// C:\Users\user\AppData\Local\STranslate
/// </summary>
private static string _ApplicationData => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\{_AppName}";
private static readonly string _AppName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
}
}

Binary file not shown.

@ -1,151 +0,0 @@
<Window x:Class="STranslate.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:STranslate.ViewModel"
mc:Ignorable="d"
Name="Mwin"
Background="Transparent"
WindowStartupLocation="CenterScreen"
MouseLeftButtonDown="Window_MouseLeftButtonDown"
AllowsTransparency="True"
ShowInTaskbar="False"
ResizeMode="NoResize"
KeyDown="Window_KeyDown"
Topmost="True"
Deactivated="Window_Deactivated"
WindowStyle="None"
SizeToContent="Height"
Width="400"
Icon="/Images/translate.ico">
<Window.DataContext>
<vm:MainVM />
</Window.DataContext>
<Border Style="{DynamicResource BorderMainStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5*" />
<RowDefinition Height="*" />
<RowDefinition Height="7*" />
</Grid.RowDefinitions>
<!--header-->
<Grid x:Name="Header">
<Button x:Name="TopmostBtn"
Template="{DynamicResource ButtonTemplateUnTopmost}"
Click="Top_Click"/>
<Button Width="auto"
Template="{DynamicResource ButtonTemplateTheme}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,100,0"
Command="{Binding ThemeConvertCmd}"
CommandParameter="{Binding ElementName=Mwin}"/>
<ComboBox Style="{DynamicResource cmbstyle}"
Margin="0,5,10,0"
ItemsSource="{Binding TranslationInterface}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedTranslationInterface}"
HorizontalAlignment="Right"/>
</Grid>
<!--input-->
<Grid x:Name="Input"
Grid.Row="1"
Margin="10,0,10,0">
<!--输入框-->
<Border x:Name="BorderInput"
Style="{DynamicResource BorderInOutputStyle}">
<Grid>
<TextBox x:Name="TextBoxInput"
Style="{DynamicResource TextBoxInputStyle}"
Text="{Binding InputTxt,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding TranslateCmd}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<Button Template="{DynamicResource ButtonTemplate}"
Visibility="{Binding InputTxt,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyInputCmd}"/>
<Border Style="{DynamicResource LanguageMarkBorderStyle}"
Visibility="{Binding IdentifyLanguage,Converter={StaticResource String2VisibilityConverter}}">
<StackPanel Margin="5,2"
Orientation="Horizontal">
<TextBlock Text="识别为 "
Style="{DynamicResource LanguageMarkTextBlockStyle}"/>
<TextBlock Text="{Binding IdentifyLanguage}"
Foreground="#af67c1"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
</Grid>
<!--mid-->
<StackPanel x:Name="MidArea"
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<TextBlock Text="当前语言: "
Style="{DynamicResource MidStyle}"/>
<ComboBox x:Name="InCombo"
Style="{DynamicResource cmbstyle}"
ItemsSource="{Binding InputCombo}"
SelectedItem="{Binding InputComboSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<Separator Margin="20,0"/>
<TextBlock Text="目标语言: "
Style="{DynamicResource MidStyle}"/>
<ComboBox x:Name="OutCombo"
Style="{DynamicResource cmbstyle}"
ItemsSource="{Binding OutputCombo}"
SelectedItem="{Binding OutputComboSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<!--output-->
<Grid x:Name="Output"
Margin="10,0,10,10"
Grid.Row="3">
<!--输出框-->
<Border x:Name="BorderOutput"
Style="{DynamicResource BorderInOutputStyle}"
Height="{Binding ElementName=Output, Path=Height}">
<Grid>
<TextBox x:Name="TextBoxOutput"
Style="{DynamicResource TextBoxOutputStyle}"
Text="{Binding OutputTxt}"/>
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<!--普通复制-->
<Button Template="{DynamicResource ButtonTemplate}"
Visibility="{Binding OutputTxt,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyResultCmd}"/>
<!--蛇形复制-->
<Button Margin="5,0"
Template="{DynamicResource ButtonTemplateSnakeCopy}"
Visibility="{Binding SnakeRet,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySnakeResultCmd}"/>
<!--小驼峰复制-->
<Button Template="{DynamicResource ButtonTemplateSmallHumpCopy}"
Visibility="{Binding SmallHumpRet,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySmallHumpResultCmd}"/>
<!--大驼峰复制-->
<Button Margin="5,0"
Template="{DynamicResource ButtonTemplateLargeHumpCopy}"
Visibility="{Binding LargeHumpRet,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyLargeHumpResultCmd}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Window>

@ -1,296 +0,0 @@
using STranslate.Helper;
using STranslate.ViewModel;
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
namespace STranslate
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MainVM vm;
public MainWindow()
{
InitializeComponent();
vm = (MainVM)DataContext;
InitView();
InitialTray();
//if (HotKeys.InputTranslate.Conflict || HotKeys.CrosswordTranslate.Conflict || HotKeys.ScreenShotTranslate.Conflict)
//{
// MessageBox.Show("全局快捷键有冲突,请您到设置中重新设置");
//}
}
private void InitialTray()
{
notifyIcon.Text = "STranslate";
//notifyIcon.BalloonTipText = "STranslate 已启动";
notifyIcon.Icon = new System.Drawing.Icon(Application.GetResourceStream(new Uri("Images/translate.ico", UriKind.Relative)).Stream);
notifyIcon.Visible = true;
//notifyIcon.ShowBalloonTip(1000);
notifyIcon.MouseDoubleClick += NotifyIcon_MouseDoubleClick;
System.Windows.Forms.MenuItem CrossWordTranslateMenuItemBTN = new System.Windows.Forms.MenuItem("划词翻译");
CrossWordTranslateMenuItemBTN.Click += new EventHandler(CrossWordTranslateMenuItem_Click);
//当失去焦点后无法从托盘处获取选中文本
CrossWordTranslateMenuItemBTN.Visible = false;
System.Windows.Forms.MenuItem ScreenshotTranslateMenuItemBTN = new System.Windows.Forms.MenuItem("截图翻译");
ScreenshotTranslateMenuItemBTN.Click += new EventHandler(ScreenshotTranslateMenuItem_Click);
ScreenshotTranslateMenuItemBTN.Enabled = false;
System.Windows.Forms.MenuItem InputTranslateMenuItemBTN = new System.Windows.Forms.MenuItem("输入翻译");
InputTranslateMenuItemBTN.Click += new EventHandler(InputTranslateMenuItem_Click);
System.Windows.Forms.MenuItem OpenMainWinBTN = new System.Windows.Forms.MenuItem("显示主界面");
OpenMainWinBTN.Click += new EventHandler(OpenMainWin_Click);
System.Windows.Forms.MenuItem AutoStartBTN = new System.Windows.Forms.MenuItem("开机自启");
AutoStartBTN.Click += new EventHandler(AutoStart_Click);
AutoStartBTN.Checked = StartupHelper.IsStartup();
System.Windows.Forms.MenuItem ExitBTN = new System.Windows.Forms.MenuItem("退出");
ExitBTN.Click += new EventHandler(Exit_Click);
System.Windows.Forms.MenuItem[] childen = new System.Windows.Forms.MenuItem[] {
CrossWordTranslateMenuItemBTN,
ScreenshotTranslateMenuItemBTN,
InputTranslateMenuItemBTN,
OpenMainWinBTN,
AutoStartBTN,
ExitBTN,
};
notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen);
}
private void AutoStart_Click(object sender, EventArgs e)
{
if (StartupHelper.IsStartup()) StartupHelper.UnSetStartup();
else StartupHelper.SetStartup();
(sender as System.Windows.Forms.MenuItem).Checked = StartupHelper.IsStartup();
}
/// <summary>
/// 移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
/// <summary>
/// 软件运行时快捷键
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_KeyDown(object sender, KeyEventArgs e)
{
//最小化 Esc
if (e.Key == Key.Escape)
{
this.Hide();
//取消置顶
TopmostBtn.SetResourceReference(TemplateProperty, _UnTopmostTemplateName);
}
//置顶 Ctrl+Shift+T
if (e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Control)
&& e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift)
&& e.Key == Key.T)
{
Top_Click(null, null);
}
//退出 Ctrl+Shift+Q
if (e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Control)
&& e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift)
&& e.Key == Key.Q)
{
Exit_Click(null, null);
}
}
/// <summary>
/// 监听全局快捷键
/// </summary>
/// <param name="e"></param>
protected override void OnSourceInitialized(EventArgs e)
{
//base.OnSourceInitialized(e);
IntPtr handle = new WindowInteropHelper(this).Handle;
HotkeysHelper.RegisterHotKey(handle);
HwndSource source = HwndSource.FromHwnd(handle);
source.AddHook(WndProc);
}
/// <summary>
/// 热键的功能
/// </summary>
/// <param name="m"></param>
protected IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handle)
{
switch (msg)
{
case 0x0312: //这个是window消息定义的 注册的热键消息
//Console.WriteLine(wParam.ToString());
if (wParam.ToString().Equals(HotkeysHelper.InputTranslateId + ""))
{
this.InputTranslateMenuItem_Click(null, null);
}
else if (wParam.ToString().Equals(HotkeysHelper.CrosswordTranslateId + ""))
{
this.CrossWordTranslateMenuItem_Click(null, null);
}
#if false
else if (wParam.ToString().Equals(HotkeysHelper.ScreenShotTranslateId + ""))
{
this.ScreenshotTranslateMenuItem_Click(null, null);
}
#endif
else if (wParam.ToString().Equals(HotkeysHelper.OpenMainWindowId + ""))
{
this.OpenMainWin_Click(null, null);
}
break;
}
return IntPtr.Zero;
}
/// <summary>
/// 非激活窗口则隐藏起来
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Deactivated(object sender, EventArgs e)
{
if (!_IsTopmost)
{
this.Hide();
}
}
/// <summary>
/// 清空输入输出框
/// </summary>
private void ClearTextBox()
{
vm.InputTxt = string.Empty;
vm.OutputTxt = string.Empty;
vm.SnakeRet = string.Empty;
vm.SmallHumpRet = string.Empty;
vm.LargeHumpRet = string.Empty;
vm.IdentifyLanguage = string.Empty;
}
/// <summary>
/// 显示主窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OpenMainWin_Click(object sender, EventArgs e)
{
this.Show();
this.Activate();
}
/// <summary>
/// 左键双击
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void NotifyIcon_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
InputTranslateMenuItem_Click(null, null);
}
/// <summary>
/// 输入翻译
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void InputTranslateMenuItem_Click(object sender, EventArgs e)
{
ClearTextBox();
OpenMainWin_Click(null, null);
TextBoxInput.Focus();
}
/// <summary>
/// 划词翻译
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CrossWordTranslateMenuItem_Click(object sender, EventArgs e)
{
ClearTextBox();
var sentence = GetWordsHelper.Get();
this.Show();
this.Activate();
this.TextBoxInput.Text = sentence.Trim();
_ = vm.Translate();
}
/// <summary>
/// 截图翻译
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScreenshotTranslateMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("开发中");
}
/// <summary>
/// 是否置顶
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Top_Click(object sender, RoutedEventArgs e)
{
if (_IsTopmost)
{
TopmostBtn.SetResourceReference(TemplateProperty, _UnTopmostTemplateName);
}
else
{
TopmostBtn.SetResourceReference(TemplateProperty, _TopmostTemplateName);
}
_IsTopmost = !_IsTopmost;
}
/// <summary>
/// 退出
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Exit_Click(object sender, EventArgs e)
{
notifyIcon.Dispose();
Environment.Exit(0);
}
private void InitView()
{
this.Activate();
this.TextBoxInput.Focus();
}
private System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon();
private bool _IsTopmost { get; set; }
private readonly string _TopmostTemplateName = "ButtonTemplateTopmost";
private readonly string _UnTopmostTemplateName = "ButtonTemplateUnTopmost";
}
}

@ -0,0 +1,173 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Model
{
public class Hotkeys
{
[JsonProperty("inputTranslate")]
public InputTranslate InputTranslate { get; set; }
[JsonProperty("crosswordTranslate")]
public CrosswordTranslate CrosswordTranslate { get; set; }
[JsonProperty("screenShotTranslate")]
public ScreenShotTranslate ScreenShotTranslate { get; set; }
[JsonProperty("openMainWindow")]
public OpenMainWindow OpenMainWindow { get; set; }
}
public class InputTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class CrosswordTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class ScreenShotTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class OpenMainWindow
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class Server
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("api")]
public string Api { get; set; }
}
public class ConfigModel
{
/// <summary>
/// 最大历史记录数量
/// </summary>
[JsonProperty("maxHistoryCount")]
public int MaxHistoryCount { get; set; }
/// <summary>
/// 自动识别语种标度
/// </summary>
[JsonProperty("autoScale")]
public double AutoScale { get; set; }
/// <summary>
/// 取词间隔
/// </summary>
[JsonProperty("wordPickupInterval")]
public double WordPickupInterval { get; set; }
/// <summary>
/// 是否亮色模式
/// </summary>
[JsonProperty("isBright")]
public bool IsBright { get; set; }
[JsonProperty("sourceLanguage")]
public string SourceLanguage { get; set; }
[JsonProperty("targetLanguage")]
public string TargetLanguage { get; set; }
[JsonProperty("selectServer")]
public int SelectServer { get; set; }
/// <summary>
/// 服务
/// </summary>
[JsonProperty("servers")]
public Server[] Servers { get; set; }
/// <summary>
/// 热键
/// </summary>
[JsonProperty("hotkeys")]
public Hotkeys Hotkeys { get; set; }
public ConfigModel()
{
}
public ConfigModel InitialConfig()
{
return new ConfigModel
{
MaxHistoryCount = 100,
AutoScale = 0.8,
WordPickupInterval = 200,
IsBright = true,
SourceLanguage = LanguageEnum.AUTO.GetDescription(),
TargetLanguage = LanguageEnum.AUTO.GetDescription(),
SelectServer = 0,
Servers = new Server[]
{
new Server
{
Name = "zggsong",
Api = "https://dfree.deno.dev/translate"
},
new Server
{
Name = "zu1k",
Api = "https://deepl.deno.dev/translate"
},
new Server
{
Name = "local",
Api = "http://127.0.0.1:8000/translate"
}
},
Hotkeys = new Hotkeys
{
InputTranslate = new InputTranslate
{
Modifiers = 1,
Key = 65,
Text = "Alt + A",
Conflict = false,
},
CrosswordTranslate = new CrosswordTranslate
{
Modifiers = 1,
Key = 68,
Text = "Alt + D",
Conflict = false,
},
ScreenShotTranslate = new ScreenShotTranslate
{
Modifiers = 1,
Key = 83,
Text = "Alt + S",
Conflict = false,
},
OpenMainWindow = new OpenMainWindow
{
Modifiers = 1,
Key = 71,
Text = "Alt + G",
Conflict = false,
},
}
};
}
}
}

@ -0,0 +1,38 @@
using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Model
{
[Table("Histories")]
public class SqliteModel
{
[PrimaryKey, AutoIncrement]
[Column("id")]
public int Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("source_lang")]
public string SourceLang { get; set; }
[Column("target_lang")]
public string TargetLang { get; set; }
[Column("source_text")]
public string SourceText { get; set; }
[Column("target_text")]
public string TargetText { get; set; }
[Column("api")]
public string Api { get; set; }
[Column("remark")]
public string Remark { get; set; }
}
}

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Model
{
public class TranslationInterface
{
public string Name { get; set; }
public string Api { get; set; }
}
}

@ -0,0 +1,20 @@
using System;
using System.Windows.Data;
namespace STranslate.Model
{
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double w = System.Convert.ToDouble(value);
return w + 30;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

@ -47,6 +47,6 @@ using System.Windows;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.1.0")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyVersion("0.2.6.0")]
[assembly: AssemblyFileVersion("0.2.6.0")]
[assembly: Guid("CE252DD8-179F-4544-9989-453F5DEA378D")]

@ -30,6 +30,8 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -43,25 +45,52 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
  <AllowedReferenceRelatedFileExtensions>
    <!-- 阻止默认的 XML 和 PDB 文件复制到 RELEASE 的输出目录. 只有*.allowedextension 扩展名的文件可以被包含, 当然这个扩展的文件并不存在.-->
    .allowedextension
  </AllowedReferenceRelatedFileExtensions><PlatformTarget>AnyCPU</PlatformTarget><DebugType>none</DebugType><Optimize>true</Optimize><OutputPath>bin\Release\</OutputPath><DefineConstants>TRACE</DefineConstants><ErrorReport>prompt</ErrorReport><WarningLevel>4</WarningLevel><Prefer32Bit>false</Prefer32Bit><GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies></PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Images\translate.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.39\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SQLite-net, Version=1.8.116.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\sqlite-net-pcl.1.8.116\lib\netstandard2.0\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.4.976, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.bundle_green.2.0.4\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=2.0.4.976, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.2.0.4\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.4.976, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.bundle_green.2.0.4\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.4.976, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Speech" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
@ -73,22 +102,33 @@
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="Tesseract, Version=5.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Tesseract.5.2.0\lib\net48\Tesseract.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WpfScreenHelper, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\WpfScreenHelper.2.1.0\lib\net40\WpfScreenHelper.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Helper\ConfigHelper.cs" />
<Compile Include="Helper\GetWordsHelper.cs" />
<Compile Include="Helper\HotkeysHelper.cs" />
<Compile Include="Helper\MvvmHelper.cs" />
<Compile Include="Helper\NativeMethodHelper.cs" />
<Compile Include="Helper\StartupHelper.cs" />
<Compile Include="Model\TranslateInterface.cs" />
<Compile Include="Helper\Processhelper.cs" />
<Compile Include="Helper\SqliteHelper.cs" />
<Compile Include="Helper\ShortcutHelper.cs" />
<Compile Include="Model\ConfigModel.cs" />
<Compile Include="Model\SqliteModel.cs" />
<Compile Include="Model\VisibilityConverter.cs" />
<Compile Include="Model\WidthConverter.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@ -96,10 +136,15 @@
</Compile>
<Compile Include="Util\Util.cs" />
<Compile Include="ViewModel\MainVM.cs" />
<Compile Include="View\UserControlInput.xaml.cs">
<DependentUpon>UserControlInput.xaml</DependentUpon>
<Compile Include="ViewModel\ScreenShotVM.cs" />
<Compile Include="ViewModel\SettingsVM.cs" />
<Compile Include="View\ScreenShotWindow.xaml.cs">
<DependentUpon>ScreenShotWindow.xaml</DependentUpon>
</Compile>
<Compile Include="View\SettingsWindow.xaml.cs">
<DependentUpon>SettingsWindow.xaml</DependentUpon>
</Compile>
<Page Include="MainWindow.xaml">
<Page Include="View\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
@ -107,7 +152,7 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<Compile Include="View\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
@ -143,7 +188,11 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="View\UserControlInput.xaml">
<Page Include="View\ScreenShotWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="View\SettingsWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -167,6 +216,12 @@
<Resource Include="Images\iconfont.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Content Include="ClearCache.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="tessdata\eng.traineddata">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@ -202,6 +257,14 @@
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Tesseract.5.2.0\build\Tesseract.targets" Condition="Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tesseract.5.2.0\build\Tesseract.targets'))" />
<Error Condition="!Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
</Target>
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
</Project>

@ -1,5 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--引入字体文件-->
<Style x:Key="IconStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/STranslate;component/Images/#iconfont"/>
</Style>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/STranslate;component/Style/Dark/DictionaryButtonDark.xaml"/>

@ -19,7 +19,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe994;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -39,7 +39,7 @@
Padding="5"
HorizontalAlignment="Left"
Margin="8,5,0,0"
MaxHeight="30">
Height="30">
<TextBlock Style="{StaticResource IconStyle}"
FontSize="21"
VerticalAlignment="Center"
@ -69,7 +69,30 @@
FontSize="22"
VerticalAlignment="Center"
Text="&#xe9ba;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="#47484c"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="#35333c"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--speak-->
<ControlTemplate x:Key="ButtonTemplateSpeak" TargetType="Button">
<Border x:Name="border"
CornerRadius="5"
Margin="0,0,5,0"
Padding="4"
MaxHeight="25">
<TextBlock Style="{StaticResource IconStyle}"
FontSize="17"
VerticalAlignment="Center"
Text="&#xe610;"
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -91,7 +114,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe692;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -113,7 +136,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe600;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -135,7 +158,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe602;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -157,7 +180,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe601;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -168,4 +191,17 @@
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--ToolTip-->
<ControlTemplate x:Key="ToolTipTemplate"
TargetType="ToolTip">
<Border CornerRadius="3"
BorderThickness="1"
BorderBrush="#393c43"
Background="#2e323a"
Padding="4">
<TextBlock Text="{TemplateBinding Name}"
Foreground="#abb2bf"/>
</Border>
</ControlTemplate>
</ResourceDictionary>

@ -1,36 +1,33 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--引入字体文件-->
<Style x:Key="IconStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/STranslate;component/Images/#iconfont"/>
</Style>
<!--Combox-->
<Style TargetType="{x:Type ComboBox}" x:Key="cmbstyle">
<Setter Property="Background" Value="#282c34"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<!--ComBoxItem-->
<Style TargetType="ComboBoxItem">
<Setter Property="MinHeight" Value="22"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Back"
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"></ContentPresenter>
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Back" Property="Background" Value="#47484c"></Setter>
<Setter TargetName="Back" Property="Background" Value="#47484c"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Back" Property="Background" Value="#47484c"></Setter>
<Setter TargetName="Back" Property="Background" Value="#47484c"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@ -42,7 +39,8 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30" Background="{TemplateBinding Background}" >
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30"
Background="#282c34" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
@ -72,10 +70,10 @@
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#282c34"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#282c34"/>
</Trigger>
</Style.Triggers>
</Style>
@ -95,7 +93,7 @@
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{StaticResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{DynamicResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@ -150,9 +148,6 @@
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="2" ShadowDepth="0" Opacity="0.5"/>
</Border.Effect>
<ScrollViewer Margin="4,6,4,6" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<!-- StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="#282c34"/>
@ -160,11 +155,6 @@
</Border>
</Popup>
</Grid>
<Border.Effect>
<DropShadowEffect ShadowDepth="-1" Opacity="0.3" Color="#FF969696" BlurRadius="2"/>
</Border.Effect>
</Border>
</ControlTemplate>
</Setter.Value>

@ -2,10 +2,12 @@
xmlns:model="clr-namespace:STranslate.Model"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<model:VisibilityConverter x:Key="String2VisibilityConverter"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style x:Key="BorderMainStyle"
TargetType="Border">
<Setter Property="Background" Value="#2e323a"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="BorderBrush" Value="#393c43"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="10"/>
</Style>
@ -19,11 +21,11 @@
<Style x:Key="TextBoxInputStyle"
TargetType="TextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="0"/>
<!--光标颜色-->
<Setter Property="CaretBrush" Value="WhiteSmoke"/>
<Setter Property="CaretBrush" Value="#abb2bf"/>
<!--选区颜色-->
<Setter Property="SelectionBrush" Value="#404856"/>
<Setter Property="Margin" Value="10,10,5,35"/>
@ -45,13 +47,13 @@
</Style>
<Style x:Key="LanguageMarkTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="#eaeaea"/>
<Setter Property="Foreground" Value="#cecece"/>
</Style>
<Style x:Key="TextBoxOutputStyle"
TargetType="TextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="IsReadOnly" Value="True"/>
@ -69,6 +71,6 @@
<Style x:Key="MidStyle"
TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
</Style>
</ResourceDictionary>

@ -81,6 +81,29 @@
</ControlTemplate.Triggers>
</ControlTemplate>
<!--speak-->
<ControlTemplate x:Key="ButtonTemplateSpeak" TargetType="Button">
<Border x:Name="border"
CornerRadius="5"
Margin="0,0,5,0"
Padding="4"
MaxHeight="25">
<TextBlock Style="{StaticResource IconStyle}"
FontSize="17"
VerticalAlignment="Center"
Text="&#xe610;"
Foreground="#515151"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="#eaeaea"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="#dddddd"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--普通复制-->
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border x:Name="border"
@ -168,4 +191,16 @@
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--ToolTip-->
<ControlTemplate x:Key="ToolTipTemplate"
TargetType="ToolTip">
<Border CornerRadius="3"
BorderThickness="1"
BorderBrush="#dfdfdf"
Background="#f6f6f6"
Padding="4">
<TextBlock Text="{TemplateBinding Name}"/>
</Border>
</ControlTemplate>
</ResourceDictionary>

@ -1,35 +1,31 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--引入字体文件-->
<Style x:Key="IconStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/STranslate;component/Images/#iconfont"/>
</Style>
<!--Combox-->
<Style TargetType="{x:Type ComboBox}" x:Key="cmbstyle">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<!--ComBoxItem-->
<Style TargetType="ComboBoxItem">
<Setter Property="MinHeight" Value="22"></Setter>
<Setter Property="MinWidth" Value="40"></Setter>
<Setter Property="MinHeight" Value="22"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Back"
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"></ContentPresenter>
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Back" Property="Background" Value="#eaeaea"></Setter>
<Setter TargetName="Back" Property="Background" Value="#eaeaea"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Back" Property="Background" Value="#eaeaea"></Setter>
<Setter TargetName="Back" Property="Background" Value="#eaeaea"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@ -41,7 +37,8 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30" Background="{TemplateBinding Background}" >
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30"
Background="#f6f6f6" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
@ -59,7 +56,7 @@
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
<ToggleButton.Style >
<Style TargetType="ToggleButton">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
@ -71,10 +68,10 @@
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
</Trigger>
</Style.Triggers>
</Style>
@ -88,13 +85,13 @@
ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{StaticResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{DynamicResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@ -149,21 +146,13 @@
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="2" ShadowDepth="0" Opacity="0.5"/>
</Border.Effect>
<ScrollViewer Margin="4,6,4,6" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<!-- StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="White"/>
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="#f6f6f6"/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
<Border.Effect>
<DropShadowEffect ShadowDepth="-1" Opacity="0.3" Color="#FF969696" BlurRadius="2"/>
</Border.Effect>
</Border>
</ControlTemplate>
</Setter.Value>

@ -2,10 +2,12 @@
xmlns:model="clr-namespace:STranslate.Model"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<model:VisibilityConverter x:Key="String2VisibilityConverter"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style x:Key="BorderMainStyle"
TargetType="Border">
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="BorderBrush" Value="#acacac"/>
<Setter Property="BorderBrush" Value="#dfdfdf"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="10"/>
</Style>

@ -1,13 +1,20 @@
using Newtonsoft.Json;
using IWshRuntimeLibrary;
using Newtonsoft.Json;
using STranslate.Model;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Windows;
using System.Windows.Media;
using Tesseract;
namespace STranslate.Util
{
@ -175,5 +182,145 @@ namespace STranslate.Util
}
}
#endregion
#region GenString
/// <summary>
/// 构造蛇形结果
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public static string GenSnakeString(List<string> req)
{
var ret = string.Empty;
req.ForEach(x =>
{
ret += "_" + x.ToLower();
});
return ret.Substring(1);
}
/// <summary>
/// 构造驼峰结果
/// </summary>
/// <param name="req"></param>
/// <param name="isSmallHump">是否为小驼峰</param>
/// <returns></returns>
public static string GenHumpString(List<string> req, bool isSmallHump)
{
string ret = string.Empty;
var array = req.ToArray();
for (var j = 0; j < array.Length; j++)
{
char[] chars = array[j].ToCharArray();
if (j == 0 && isSmallHump) chars[0] = char.ToLower(chars[0]);
else chars[0] = char.ToUpper(chars[0]);
for (int i = 1; i < chars.Length; i++)
{
chars[i] = char.ToLower(chars[i]);
}
ret += new string(chars);
}
return ret;
}
/// <summary>
/// 提取英文
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ExtractEngString(string str)
{
Regex regex = new Regex("[a-zA-Z]+");
MatchCollection mMactchCol = regex.Matches(str);
string strA_Z = string.Empty;
foreach (Match mMatch in mMactchCol)
{
strA_Z += mMatch.Value;
}
return strA_Z;
}
#endregion
#region Screenshot
/// <summary>
/// Tesseract 库获取文本
/// </summary>
/// <param name="bmp"></param>
/// <returns></returns>
public static string TesseractGetText(Bitmap bmp)
{
try
{
using (var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default))
//using (var engine = new TesseractEngine(@"./tessdata", "chi_sim", EngineMode.Default))
{
using(var pix = PixConverter.ToPix(bmp))
{
using (var page = engine.Process(pix))
{
return page.GetText();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
public static ImageBrush BitmapToImageBrush(Bitmap bmp)
{
ImageBrush brush = new ImageBrush();
IntPtr hBitmap = bmp.GetHbitmap();
ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
brush.ImageSource = wpfBitmap;
FlushMemory();
return brush;
}
/// <summary>
/// 清理内存
/// </summary>
public static void FlushMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
Helper.NativeMethodHelper.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
#endregion
#region Shortcut
public static void CreateShortcut()
{
string deskTop = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop);
string dirPath = System.Environment.CurrentDirectory;
string exePath = Assembly.GetExecutingAssembly().Location;
System.Diagnostics.FileVersionInfo exeInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(exePath);
if (System.IO.File.Exists(string.Format(@"{0}\STranslate.lnk", deskTop)))
{
System.IO.File.Delete(string.Format(@"{0}\STranslate.lnk",deskTop));//删除原来的桌面快捷键方式
return;
}
WshShell shell = new WshShell();
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + "STranslate.lnk");
shortcut.TargetPath = @exePath; //目标文件
shortcut.WorkingDirectory = dirPath; //目标文件夹
shortcut.WindowStyle = 1; //目标应用程序的窗口状态分为普通、最大化、最小化【1,3,7】
shortcut.Description = "自动更新程序"; //描述
shortcut.IconLocation = string.Format(@"{0}\64.ico", dirPath); //快捷方式图标
shortcut.Arguments = "";
shortcut.Hotkey = "SHIFT+DELETE"; // 快捷键
shortcut.Save();
}
#endregion
}
}

@ -0,0 +1,254 @@
<Window x:Class="STranslate.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="clr-namespace:STranslate.Model"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
x:Name="Mwin"
Background="Transparent"
WindowStartupLocation="CenterScreen"
AllowsTransparency="True"
ShowInTaskbar="False"
ResizeMode="NoResize"
Topmost="True"
WindowStyle="None"
SizeToContent="Height"
Width="400"
FontFamily="{DynamicResource {x:Static SystemFonts.CaptionFontFamilyKey}}"
Icon="/Images/translate.ico">
<Window.Resources>
<model:WidthConverter x:Key="WidthConverter"/>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Modifiers="Ctrl+Shift"
Key="Q"
Command="{Binding ExitCmd}"/>
<KeyBinding Modifiers="Ctrl+Shift"
Key="T"
Command="{Binding TopmostCmd}"
CommandParameter="{Binding ElementName=TopmostBtn, Mode=OneWay}"/>
<KeyBinding Modifiers="Ctrl+Shift"
Key="R"
Command="{Binding ThemeConvertCmd}"/>
<KeyBinding Key="Esc"
Command="{Binding EscCmd}"
CommandParameter="{Binding ElementName=TopmostBtn, Mode=OneWay}"/>
</Window.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding MouseLeftDownCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Deactivated">
<i:InvokeCommandAction Command="{Binding DeactivatedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Border Style="{DynamicResource BorderMainStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5*"/>
<RowDefinition Height="*" />
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<!--header-->
<Grid x:Name="Header">
<Button x:Name="TopmostBtn"
Command="{Binding TopmostCmd}"
CommandParameter="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}"
Template="{DynamicResource ButtonTemplateUnTopmost}"/>
<Button Width="auto"
Template="{DynamicResource ButtonTemplateTheme}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,100,0"
Command="{Binding ThemeConvertCmd}"
CommandParameter="{Binding ElementName=Mwin}"/>
<ComboBox Style="{DynamicResource cmbstyle}"
Margin="0,5,10,0"
ItemsSource="{Binding TranslationInterface}"
SelectedItem="{Binding SelectedTranslationInterface, Mode=TwoWay, NotifyOnSourceUpdated=True}"
DisplayMemberPath="Name"
HorizontalAlignment="Right">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectLangChangedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</Grid>
<!--input-->
<Grid x:Name="Input"
Grid.Row="1"
Margin="10,0,10,0">
<!--输入框-->
<Border x:Name="BorderInput"
Style="{DynamicResource BorderInOutputStyle}">
<Grid>
<TextBox x:Name="TextBoxInput"
Style="{DynamicResource TextBoxInputStyle}"
Text="{Binding InputTxt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding TranslateCmd}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<Button Template="{DynamicResource ButtonTemplateSpeak}"
Visibility="{Binding InputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding SourceSpeakCmd}"/>
<Button Template="{DynamicResource ButtonTemplate}"
Click="Copy_Click"
Visibility="{Binding InputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyInputCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制输入内容" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<Border Style="{DynamicResource LanguageMarkBorderStyle}"
Visibility="{Binding IdentifyLanguage, Converter={StaticResource String2VisibilityConverter}}">
<StackPanel Margin="5,2"
Orientation="Horizontal">
<TextBlock Text="识别为 "
Style="{DynamicResource LanguageMarkTextBlockStyle}"/>
<TextBlock Text="{Binding IdentifyLanguage}"
Foreground="#af67c1"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
</Grid>
<!--toast-->
<Border x:Name="Toast"
CornerRadius="12"
Grid.Row="0"
Grid.RowSpan="2"
VerticalAlignment="Top"
Visibility="Visible"
Margin="0,-40"
Width="{Binding ElementName=toastTxt, Path=ActualWidth,Converter={StaticResource WidthConverter}}"
BorderBrush="Transparent"
Background="#65c248">
<WrapPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<TextBlock Text="&#xe632;"
FontSize="16"
Foreground="White"
Padding="5,10"
Style="{StaticResource IconStyle}"/>
<TextBlock x:Name="toastTxt"
Background="Transparent"
Foreground="#fff"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="0,5,10,5"
FontSize="16"/>
</WrapPanel>
</Border>
<!--mid-->
<StackPanel x:Name="MidArea"
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<TextBlock Text="当前语言: "
Style="{DynamicResource MidStyle}"/>
<ComboBox x:Name="InCombo"
Style="{DynamicResource cmbstyle}"
ItemsSource="{Binding InputCombo}"
SelectedItem="{Binding InputComboSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectLangChangedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Separator Margin="20,0"/>
<TextBlock Text="目标语言: "
Style="{DynamicResource MidStyle}"/>
<ComboBox x:Name="OutCombo"
Style="{DynamicResource cmbstyle}"
ItemsSource="{Binding OutputCombo}"
SelectedItem="{Binding OutputComboSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectLangChangedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
<!--output-->
<Grid x:Name="Output"
Margin="10,0,10,10"
Grid.Row="3">
<!--输出框-->
<Border x:Name="BorderOutput"
Style="{DynamicResource BorderInOutputStyle}"
Height="{Binding Height, ElementName=Output}">
<Grid>
<TextBox x:Name="TextBoxOutput"
Style="{DynamicResource TextBoxOutputStyle}"
Text="{Binding OutputTxt}"/>
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<!--语音-->
<Button Template="{DynamicResource ButtonTemplateSpeak}"
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding TargetSpeakCmd}"/>
<!--普通复制-->
<Button Template="{DynamicResource ButtonTemplate}"
Click="Copy_Click"
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="直接复制结果" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--蛇形复制-->
<Button Margin="5,0"
Click="Copy_Click"
Template="{DynamicResource ButtonTemplateSnakeCopy}"
Visibility="{Binding SnakeRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySnakeResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为蛇形字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--小驼峰复制-->
<Button Template="{DynamicResource ButtonTemplateSmallHumpCopy}"
Click="Copy_Click"
Visibility="{Binding SmallHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySmallHumpResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为小驼峰字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--大驼峰复制-->
<Button Margin="5,0"
Click="Copy_Click"
Template="{DynamicResource ButtonTemplateLargeHumpCopy}"
Visibility="{Binding LargeHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyLargeHumpResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为大驼峰字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Window>

@ -0,0 +1,202 @@
using STranslate.Helper;
using STranslate.ViewModel;
using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows.Media;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
namespace STranslate.View
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = vm;
vm.Mainwin = this;
InitialTray();
Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
InitIcon();
}
/// <summary>
/// 监听全局快捷键
/// </summary>
/// <param name="e"></param>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
this.Hide();
HotkeysHelper.InitialHook(this);
HotkeysHelper.Register(HotkeysHelper.InputTranslateId, () =>
{
vm.InputTranslate();
});
HotkeysHelper.Register(HotkeysHelper.CrosswordTranslateId, () =>
{
vm.CrossWordTranslate();
});
HotkeysHelper.Register(HotkeysHelper.ScreenShotTranslateId, () =>
{
vm.ScreenShotTranslate();
});
HotkeysHelper.Register(HotkeysHelper.OpenMainWindowId, () =>
{
vm.OpenMainWin();
});
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict)
{
MessageBox.Show("全局快捷键有冲突,请前往软件首选项中修改...");
}
}
private void Copy_Click(object sender, RoutedEventArgs e)
{
var o = sender as System.Windows.Controls.Button;
toastTxt.Text = (o.ToolTip as System.Windows.Controls.ToolTip).Name;
//创建一个一个对象,对两个值在时间线上进行动画处理(移动距离,移动到的位置)
var da = new DoubleAnimation();
//设定动画时间线
da.Duration = new Duration(TimeSpan.FromSeconds(0.8));
//设定移动动画的结束值控件向下移动60个像素向上移动则是-60
da.To = 50;
da.From = 0;
da.AccelerationRatio = 0.2;
da.DecelerationRatio = 0.8;
da.AutoReverse = true;
//btnFlash要进行动画操作的控件名
Toast.RenderTransform = new TranslateTransform();
//开始进行动画处理
Toast.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da);
}
private MainVM vm = MainVM.Instance;
public readonly NotifyIcon NotifyIcon = new NotifyIcon();
#region Initial TrayIcon
private void InitIcon()
{
var stream = Application
.GetResourceStream(new Uri("Images/translate.ico", UriKind.Relative))?.Stream;
if (NotifyIcon.Icon != null)
{
NotifyIcon.Icon.Dispose();
}
if (stream != null)
{
NotifyIcon.Icon = new System.Drawing.Icon(stream);
}
}
private void InitialTray()
{
var app = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly()?.Location);
NotifyIcon.Text = $@"{app} {SettingsVM.Instance.Version}";
InitIcon();
NotifyIcon.Visible = true;
NotifyIcon.BalloonTipText = $@"{app} already started...";
NotifyIcon.ShowBalloonTip(500);
NotifyIcon.MouseDoubleClick += InputTranslateMenuItem_Click;
var inputTranslateMenuItemBtn = new MenuItem("输入翻译");
inputTranslateMenuItemBtn.Click += InputTranslateMenuItem_Click;
var screenshotTranslateMenuItemBtn = new MenuItem("截图翻译");
screenshotTranslateMenuItemBtn.Click += ScreenshotTranslateMenuItem_Click;
var crossWordTranslateMenuItemBtn = new MenuItem("划词翻译");
//CrossWordTranslateMenuItemBTN.Click += CrossWordTranslateMenuItem_Click;
//当失去焦点后无法从托盘处获取选中文本
crossWordTranslateMenuItemBtn.Enabled = false;
var openMainWinBtn = new MenuItem("显示主界面");
openMainWinBtn.Click += OpenMainWin_Click;
var preferenceBtn = new MenuItem("首选项");
preferenceBtn.Click += Preference_Click;
var exitBtn = new MenuItem("退出");
exitBtn.Click += Exit_Click;
var items = new MenuItem[] {
inputTranslateMenuItemBtn,
screenshotTranslateMenuItemBtn,
crossWordTranslateMenuItemBtn,
openMainWinBtn,
preferenceBtn,
exitBtn,
};
NotifyIcon.ContextMenu = new ContextMenu(items);
}
/// <summary>
/// 设置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Preference_Click(object sender, EventArgs e)
{
SettingsWindow window = null;
foreach (Window item in Application.Current.Windows)
{
if (item is SettingsWindow)
{
window = (SettingsWindow)item;
window.WindowState = WindowState.Normal;
window.Activate();
break;
}
}
if (window == null)
{
window = new SettingsWindow();
window.Show();
window.Activate();
}
}
private void ScreenshotTranslateMenuItem_Click(object sender, EventArgs e)
{
vm.ScreenShotTranslate();
}
private void OpenMainWin_Click(object sender, EventArgs e)
{
vm.OpenMainWin();
}
private void Exit_Click(object sender, EventArgs e)
{
vm.ExitApp(0);
}
private void InputTranslateMenuItem_Click(object sender, EventArgs e)
{
vm.InputTranslate();
}
#endregion
}
}

@ -0,0 +1,48 @@
<Window x:Class="STranslate.View.ScreenShotWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:STranslate.View"
mc:Ignorable="d"
Title="ScreenShotWindow"
Height="1" Width="1"
ShowInTaskbar="False"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Topmost="True"
Cursor="Cross"
Background="Transparent"
WindowStyle="None"
ResizeMode="NoResize"
IsTabStop="False">
<Window.InputBindings>
<KeyBinding Key="Esc"
Command="{Binding EscCmd}"/>
</Window.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown">
<i:InvokeCommandAction Command="{Binding EscCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction Command="{Binding MouseMoveCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding MouseLeftDownCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding MouseLeftUpCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Closed">
<i:InvokeCommandAction Command="{Binding ClosedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Canvas x:Name="ScreenCanvas">
<Rectangle x:Name="LeftMask" Fill="#7f7f7f" Opacity="0.6" />
<Rectangle x:Name="RightMask" Fill="#7f7f7f" Opacity="0.6" />
<Rectangle x:Name="UpMask" Fill="#7f7f7f" Opacity="0.6" />
<Rectangle x:Name="DownMask" Fill="#7f7f7f" Opacity="0.6" />
</Canvas>
</Window>

@ -1,4 +1,5 @@
using System;
using STranslate.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -10,19 +11,24 @@ using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace STranslate.View
{
/// <summary>
/// UserControlInput.xaml 的交互逻辑
/// ScreenShotWindow.xaml 的交互逻辑
/// </summary>
public partial class UserControlInput : UserControl
public partial class ScreenShotWindow : Window
{
public UserControlInput()
public ScreenShotWindow()
{
DataContext = new ScreenShotVM(this);
var datas = (DataContext as ScreenShotVM).InitView1();
InitializeComponent();
(DataContext as ScreenShotVM).InitView2(datas);
}
}
}

@ -0,0 +1,383 @@
<Window x:Name="window" x:Class="STranslate.View.SettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:STranslate.View"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
Loaded="window_Loaded"
WindowStartupLocation="CenterScreen"
Icon="/Images/translate.ico"
Title="STranslate 首选项" Height="450" Width="450">
<Window.Resources>
<ControlTemplate x:Key="buttonstyle"
TargetType="Button">
<Border x:Name="border"
CornerRadius="5"
Padding="5"
Background="#dedfde"
MaxHeight="25">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="#c6e6fc"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="#cce6f6"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="Esc"
Command="{Binding EscCmd}"
CommandParameter="{Binding ElementName=window, Mode=OneWay}"/>
</Window.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closed">
<i:InvokeCommandAction Command="{Binding ClosedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid Margin="20">
<TabControl>
<TabItem Header="常规"
Padding="10,2">
<StackPanel Margin="20">
<GroupBox Header="开机启动">
<WrapPanel Margin="0,5,0,5">
<CheckBox Content="开机启动"
IsChecked="{Binding IsStartup}"
FontWeight="Bold">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding StartupCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding StartupCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</WrapPanel>
</GroupBox>
<GroupBox Header="语种识别(zh-en)"
ToolTip="根据英文字符占所有字符比例判断中英文">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.AutoScale, ElementName=window}"
Minimum="0.01"
Maximum="0.99"
MinWidth="200"
TickFrequency="0.01"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding AutoScale, StringFormat={}{0}}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
<GroupBox Header="历史记录数量"
ToolTip="记录记录至本地数据库,以便省去重复查询的时间,调整最大历史记录数量">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.MaxHistoryCount, ElementName=window}"
Minimum="1"
Maximum="1000"
MinWidth="200"
TickFrequency="10"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding MaxHistoryCount, StringFormat={}{0}条}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
<GroupBox Header="取词间隔"
ToolTip="划词翻译实现原理是用户用鼠标划词后模拟Ctrl+C间隔一定时间后程序再从剪切板取词如果电脑反应慢可能会出现取不到词的问题将间隔调大可以适配一些老旧的机器">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.WordPickupInterval, ElementName=window}"
Minimum="100"
Maximum="1000"
MinWidth="200"
TickFrequency="100"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding WordPickupInterval, StringFormat={}{0}ms}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Header="控制"
Padding="10,2">
<StackPanel Margin="20">
<GroupBox Header="快捷键">
<Grid Margin="20,10,20,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="划词翻译"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="CrossWordTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="1"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="CrossWord_KeyUp"/>
<Label x:Name="CrossWordHotKeyConflictLabel"
Grid.Row="1"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Label Content="截图翻译"
VerticalAlignment="Center"
Grid.Row="2"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="ScreenshotTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="2"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="Screenshot_KeyUp"/>
<Label x:Name="ScreenshotHotKeyConflictLabel"
Grid.Row="2"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Label Content="输入翻译"
VerticalAlignment="Center"
Grid.Row="3"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="InputTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="3"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="Input_KeyUp"/>
<Label x:Name="InputHotKeyConflictLabel"
Grid.Row="3"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red"/>
<Label Content="显示界面"
VerticalAlignment="Center"
Grid.Row="4"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="ShowMainwinTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="4"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="ShowMainwin_KeyUp"/>
<Label x:Name="ShowMainwinHotKeyConflictLabel"
Grid.Row="4"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Button Content="恢复默认"
Template="{StaticResource buttonstyle}"
Width="80"
Grid.Row="5"
Margin="5"
Grid.Column="1"
Click="ResetHoskeys_Click"/>
</Grid>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Header="服务"
Visibility="Collapsed"
Padding="10,2">
<GroupBox Header="DeepL API">
</GroupBox>
</TabItem>
<TabItem Header="关于"
Padding="10,2">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="20">
<WrapPanel Orientation="Horizontal">
<Image Source="/Images/translate.ico" Width="30"/>
<TextBlock VerticalAlignment="Bottom"
FontSize="18"
Margin="5,0">
<Run Text="STranslate"
FontWeight="Bold"/>
</TextBlock>
<!--<Border BorderBrush="Transparent"
Background="Black"
Margin="20,0,0,0"
Height="20"
CornerRadius="4">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Right"
Foreground="WhiteSmoke"
Padding="5,0"
Text="Built with WPF"/>
</Border>-->
</WrapPanel>
<WrapPanel Margin="0,10,0,0">
<Label Content="版本"/>
<Label x:Name="Label_Version"
DataContext="https://github.com/zggsong/stranslate/releases"
Cursor="Hand"
Content="{Binding DataContext.Version, ElementName=window}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Version, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
<Button Content="检查更新"
Margin="40,0"
Template="{StaticResource buttonstyle}"
Command="{Binding UpdateCmd}">
</Button>
</WrapPanel>
<WrapPanel>
<Label Content="开源"/>
<Label x:Name="Label_Lic"
Content="MIT License"
DataContext="https://github.com/ZGGSONG/STranslate/blob/main/LICENSE"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Lic, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="版权"/>
<Label x:Name="Label_Ccopyright"
Content="@2022 ZGGSONG"
DataContext="https://github.com/ZGGSONG"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Ccopyright, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="联系"/>
<Label x:Name="Label_Connect"
Content="zggsong@foxmail.com"
DataContext="zggsong@foxmail.com"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Connect, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="源码"/>
<Label x:Name="Label_Source" Content="https://github.com/zggsong/stranslate"
DataContext="https://github.com/ZGGSONG/STranslate"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Source, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="反馈"/>
<Label x:Name="Label_Feedback" Content="https://github.com/zggsong/stranslate/issues"
DataContext="https://github.com/ZGGSONG/STranslate/issues"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Feedback, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Window>

@ -0,0 +1,187 @@
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace STranslate.View
{
/// <summary>
/// SettingsWindow.xaml 的交互逻辑
/// </summary>
public partial class SettingsWindow : Window
{
public SettingsWindow()
{
InitializeComponent();
#if DEBUG
this.window.Topmost = true;
#endif
DataContext = ViewModel.SettingsVM.Instance;
}
private void window_Loaded(object sender, RoutedEventArgs e)
{
this.InputTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text;
this.CrossWordTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text;
this.ScreenshotTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text;
this.ShowMainwinTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text;
HotKeyConflictCheck();
}
private byte _hotkeysModifiers;
private int _hotkeysKey;
private string _hotkeysText = string.Empty;
private void HotKeyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
_hotkeysModifiers = 0;
_hotkeysKey = 0;
_hotkeysText = "";
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
StringBuilder shortcutText = new StringBuilder();
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
{
_hotkeysModifiers += 2;
shortcutText.Append("Ctrl + ");
}
if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0)
{
_hotkeysModifiers += 4;
shortcutText.Append("Shift + ");
}
if ((Keyboard.Modifiers & ModifierKeys.Alt) != 0)
{
_hotkeysModifiers += 1;
shortcutText.Append("Alt + ");
}
if (_hotkeysModifiers == 0 && (key < Key.F1 || key > Key.F12))
{
_hotkeysKey = 0;
shortcutText.Clear();
((System.Windows.Controls.TextBox)sender).Text = _hotkeysText = "";
return;
}
_hotkeysKey = KeyInterop.VirtualKeyFromKey(key);
shortcutText.Append(key.ToString());
((System.Windows.Controls.TextBox)sender).Text = _hotkeysText = shortcutText.ToString();
}
private void CrossWord_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void Input_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void Screenshot_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void ShowMainwin_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void ResetHoskeys_Click(object sender, RoutedEventArgs e)
{
CrossWordTextBox.Text = "Alt + D";
InputTextBox.Text = "Alt + A";
ScreenshotTextBox.Text = "Alt + S";
ShowMainwinTextBox.Text = "Alt + G";
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key = 68;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text = "Alt + D";
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key = 65;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text = "Alt + A";
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key = 83;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text = "Alt + S";
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key = 71;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text = "Alt + G";
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void HotKeyConflictCheck()
{
this.CrossWordHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.ScreenshotHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.InputHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.ShowMainwinHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict ? Visibility.Visible : Visibility.Hidden;
}
}
}

@ -1,39 +0,0 @@
<UserControl x:Class="STranslate.View.UserControlInput"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:STranslate.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<!--输入框-->
<Border x:Name="BorderInput"
Style="{DynamicResource BorderInOutputStyle}">
<Grid>
<TextBox x:Name="TextBoxInput"
Style="{DynamicResource TextBoxInputStyle}"
Text="{Binding InputTxt,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding TranslateCmd}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<Button Template="{DynamicResource ButtonTemplate}"
Visibility="{Binding InputTxt,Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyInputCmd}"/>
<Border Style="{DynamicResource LanguageMarkBorderStyle}"
Visibility="{Binding IdentifyLanguage,Converter={StaticResource String2VisibilityConverter}}">
<StackPanel Margin="5,2"
Orientation="Horizontal">
<TextBlock Text="识别为 "
Style="{DynamicResource LanguageMarkTextBlockStyle}"/>
<TextBlock Text="{Binding IdentifyLanguage}"
Foreground="#af67c1"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
</UserControl>

@ -1,31 +1,87 @@
using STranslate.Model;
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Threading.Tasks;
using System.Speech.Synthesis;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using STranslate.View;
using STranslate.Model;
using STranslate.Helper;
using System.Windows.Controls;
namespace STranslate.ViewModel
{
public class MainVM : BaseVM
{
public MainVM()
{
#region Initial
if (!ReadConfig())
{
ExitApp(-1);
}
InputCombo = LanguageEnumDict.Keys.ToList();
InputComboSelected = LanguageEnum.AUTO.GetDescription();
OutputCombo = LanguageEnumDict.Keys.ToList();
OutputComboSelected = LanguageEnum.AUTO.GetDescription();
_sqlHelper = new SqliteHelper();
#endregion
//初始化接口
SelectedTranslationInterface = TranslationInterface[1];
#region Common
//退出
ExitCmd = new RelayCommand((_) => true, (_) => ExitApp(0));
//置顶
TopmostCmd = new RelayCommand((_) => true, (o) =>
{
((Button)o).SetResourceReference(Control.TemplateProperty,
IsTopmost ? UnTopmostTemplateName : TopmostTemplateName);
IsTopmost = !IsTopmost;
});
//ESC
EscCmd = new RelayCommand((_) => true, (o) =>
{
//取消置顶
if (IsTopmost)
{
((Button)o).SetResourceReference(Control.TemplateProperty, UnTopmostTemplateName);
IsTopmost = !IsTopmost;
}
Mainwin.Hide();
});
//切换语言
SelectLangChangedCmd = new RelayCommand((_) => true, (_) =>
{
if (string.IsNullOrEmpty(InputTxt)) return;
IdentifyLanguage = string.Empty;
_ = Translate();
});
//移动
MouseLeftDownCmd = new RelayCommand((_) => true, (_) =>
{
Mainwin.DragMove();
});
//失去焦点
DeactivatedCmd = new RelayCommand((_) => true, (_) =>
{
if (IsTopmost) return;
_speech.SpeakAsyncCancelAll();
Mainwin.Hide();
Util.Util.FlushMemory();
});
//source speak
SourceSpeakCmd = new RelayCommand((_) => true, (_) =>
{
_speech.SpeakAsync(InputTxt);
});
//target speak
TargetSpeakCmd = new RelayCommand((_) => true, (_) =>
{
_speech.SpeakAsync(OutputTxt);
});
//复制输入
CopyInputCmd = new RelayCommand((_) => true, (_) =>
{
@ -57,20 +113,226 @@ namespace STranslate.ViewModel
{
Application.Current.Resources.MergedDictionaries[0].Source =
Application.Current.Resources.MergedDictionaries[0].Source
.ToString() == _ThemeDark ? new Uri(_ThemeDefault) : new Uri(_ThemeDark);
.ToString() == ThemeDark ? new Uri(ThemeDefault) : new Uri(ThemeDark);
});
//翻译
TranslateCmd = new RelayCommand((_) =>
{
return string.IsNullOrEmpty(InputTxt) ? false : true;
}, async (_) =>
TranslateCmd = new RelayCommand((_) => !string.IsNullOrEmpty(InputTxt), async (_) =>
{
await Translate();
});
#endregion
}
#region handle
/// <summary>
/// 清空所有
/// </summary>
private void ClearAll()
{
InputTxt = string.Empty;
OutputTxt = string.Empty;
SnakeRet = string.Empty;
SmallHumpRet = string.Empty;
LargeHumpRet = string.Empty;
IdentifyLanguage = string.Empty;
Util.Util.FlushMemory();
}
/// <summary>
/// 打开主窗口
/// </summary>
public void OpenMainWin()
{
Mainwin.Show();
Mainwin.Activate();
//TODO: need to deal with this
//TextBoxInput.Focus();
((TextBox)Mainwin.FindName("TextBoxInput"))?.Focus();
}
/// <summary>
/// 输入翻译
/// </summary>
public void InputTranslate()
{
ClearAll();
OpenMainWin();
}
/// <summary>
/// 划词翻译
/// </summary>
public void CrossWordTranslate()
{
ClearAll();
var sentence = GetWordsHelper.Get();
OpenMainWin();
InputTxt = sentence.Trim();
_ = Translate();
}
/// <summary>
/// 截屏翻译
/// </summary>
public void ScreenShotTranslate()
{
ScreenShotWindow window = null;
foreach (Window item in Application.Current.Windows)
{
if (item is ScreenShotWindow)
{
window = (ScreenShotWindow)item;
window.WindowState = WindowState.Normal;
window.Activate();
break;
}
}
if (window == null)
{
window = new ScreenShotWindow();
window.Show();
window.Activate();
}
}
/// <summary>
/// 截屏翻译Ex
/// </summary>
public void ScreenShotTranslateEx(string text)
{
InputTranslate();
InputTxt = text;
_ = Translate();
}
/// <summary>
/// 退出App
/// </summary>
public void ExitApp(int id)
{
Util.Util.FlushMemory();
Mainwin.NotifyIcon.Dispose();
Mainwin.Close();
//关闭数据库
_sqlHelper.Dispose();
//语音合成销毁
_speech.Dispose();
//注销快捷键
HotkeysHelper.UnRegisterHotKey();
if (id == 0)
{
//写入配置
WriteConfig();
}
Environment.Exit(id);
}
/// <summary>
/// 初始化配置文件
/// </summary>
/// <returns></returns>
private bool ReadConfig()
{
try
{
_globalConfig = ConfigHelper.Instance.ReadConfig<ConfigModel>();
#region 读取热键
NHotkeys = _globalConfig.Hotkeys ?? new Hotkeys
{
InputTranslate = new InputTranslate
{
Modifiers = 1,
Key = 65,
Text = "Alt + A",
Conflict = false,
},
CrosswordTranslate = new CrosswordTranslate
{
Modifiers = 1,
Key = 68,
Text = "Alt + D",
Conflict = false,
},
ScreenShotTranslate = new ScreenShotTranslate
{
Modifiers = 1,
Key = 83,
Text = "Alt + S",
Conflict = false,
},
OpenMainWindow = new OpenMainWindow
{
Modifiers = 1,
Key = 71,
Text = "Alt + G",
Conflict = false,
},
};
#endregion
//读取历史记录数量
var count = _globalConfig.MaxHistoryCount;
SettingsVM.Instance.MaxHistoryCount = (count <= 0 || count >= 1000) ? 100 : count;
//读取自动识别语种比例
var scale = _globalConfig.AutoScale;
SettingsVM.Instance.AutoScale = (scale <= 0 || scale >= 1) ? 0.8 : scale;
//读取间隔
var tmp = _globalConfig.WordPickupInterval;
SettingsVM.Instance.WordPickupInterval = (tmp == 0 || tmp > 1000 || tmp < 100) ? 200 : tmp;
//配置读取主题
Application.Current.Resources.MergedDictionaries[0].Source = _globalConfig.IsBright ? new Uri(ThemeDefault) : new Uri(ThemeDark);
//更新服务
TranslationInterface = _globalConfig.Servers.ToList();
if (TranslationInterface.Count < 1) throw new Exception("尚未配置任何翻译接口服务");
try
{
//配置读取接口
SelectedTranslationInterface = TranslationInterface[_globalConfig.SelectServer];
}
catch (Exception ex)
{
throw new Exception($"配置文件选择服务索引出错, 请修改配置文件后重试", ex);
}
//从配置读取source target
InputComboSelected = _globalConfig.SourceLanguage;
OutputComboSelected = _globalConfig.TargetLanguage;
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
private void WriteConfig()
{
try
{
ConfigHelper.Instance.WriteConfig(new ConfigModel
{
MaxHistoryCount = SettingsVM.Instance.MaxHistoryCount,
AutoScale = SettingsVM.Instance.AutoScale,
WordPickupInterval = SettingsVM.Instance.WordPickupInterval,
IsBright = Application.Current.Resources.MergedDictionaries[0].Source.ToString() == ThemeDefault ? true : false,
SourceLanguage = InputComboSelected,
TargetLanguage = OutputComboSelected,
SelectServer = TranslationInterface.FindIndex(x => x == SelectedTranslationInterface),
Servers = _globalConfig.Servers,
Hotkeys = NHotkeys,
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 自动识别语种
/// </summary>
@ -88,12 +350,12 @@ namespace STranslate.ViewModel
string.Empty);
//2. 取出上一步中所有英文字符
var engStr = GetSubString(text);
var engStr = Util.Util.ExtractEngString(text);
var ratio = (double)engStr.Length / text.Length;
//3. 判断英文字符个数占第一步所有字符个数比例,若超过一则判定原字符串为英文字符串,否则为中文字符串
if (ratio > 0.5)
//3. 判断英文字符个数占第一步所有字符个数比例,若超过一定比例则判定原字符串为英文字符串,否则为中文字符串
if (ratio > SettingsVM.Instance.AutoScale)
{
return new Tuple<string, string>(LanguageEnum.EN.GetDescription(), LanguageEnum.ZH.GetDescription());
}
@ -101,26 +363,18 @@ namespace STranslate.ViewModel
{
return new Tuple<string, string>(LanguageEnum.ZH.GetDescription(), LanguageEnum.EN.GetDescription());
}
#if false
//如果输入是中文
if (Regex.IsMatch(text, @"^[\u4e00-\u9fa5]+$"))
{
return new Tuple<string, string>(LanguageEnum.ZH.GetDescription(), LanguageEnum.EN.GetDescription());
}
else
{
return new Tuple<string, string>(LanguageEnum.EN.GetDescription(), LanguageEnum.ZH.GetDescription());
}
#endif
}
/// <summary>
/// 翻译
/// </summary>
/// <returns></returns>
public async Task Translate()
private async Task Translate()
{
try
{
if (string.IsNullOrEmpty(InputTxt.Trim()))
throw new Exception("输入值为空!");
var isEng = string.Empty;
IdentifyLanguage = string.Empty;
OutputTxt = "翻译中...";
@ -132,25 +386,41 @@ namespace STranslate.ViewModel
//自动选择目标语言
if (OutputComboSelected == LanguageEnum.AUTO.GetDescription())
{
//只有在自动的模式下读取
var resp = _sqlHelper.Query(InputTxt);
if (!string.IsNullOrEmpty(resp))
{
OutputTxt = resp;
return;
}
var autoRet = AutomaticLanguageRecognition(InputTxt);
IdentifyLanguage = autoRet.Item1;
isEng = autoRet.Item2;
translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[autoRet.Item2], LanguageEnumDict[InputComboSelected]);
_translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[autoRet.Item2], LanguageEnumDict[InputComboSelected]);
}
else
{
translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
_translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
}
//百度 Api
//var translateResp = await TranslateUtil.TranslateBaiduAsync(config.baidu.appid, config.baidu.secretKey, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
if (translateResp == string.Empty)
if (_translateResp == string.Empty)
{
OutputTxt = "翻译出错,请稍候再试...";
return;
}
OutputTxt = translateResp;
OutputTxt = _translateResp;
await Task.Run(() =>
{
_sqlHelper.Insert(DateTime.Now,
InputTxt,
OutputTxt,
LanguageEnumDict[string.IsNullOrEmpty(IdentifyLanguage) ? InputComboSelected : IdentifyLanguage],
LanguageEnumDict[string.IsNullOrEmpty(isEng) ? OutputComboSelected : isEng],
SelectedTranslationInterface.Api);
});
//如果目标语言不是英文则不进行转换
//1. 自动判断语种Tuple item2 不为 EN
@ -167,9 +437,9 @@ namespace STranslate.ViewModel
var splitList = OutputTxt.Split(' ').ToList();
if (splitList.Count > 1)
{
SnakeRet = GenSnakeString(splitList);
SmallHumpRet = GenHumpString(splitList, true); //小驼峰
LargeHumpRet = GenHumpString(splitList, false); //大驼峰
SnakeRet = Util.Util.GenSnakeString(splitList);
SmallHumpRet = Util.Util.GenHumpString(splitList, true); //小驼峰
LargeHumpRet = Util.Util.GenHumpString(splitList, false); //大驼峰
}
//System.Diagnostics.Debug.Print(SnakeRet + "\n" + SmallHumpRet + "\n" + LargeHumpRet);
}
@ -178,142 +448,102 @@ namespace STranslate.ViewModel
OutputTxt = ex.Message;
}
}
/// <summary>
/// 构造蛇形结果
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
private string GenSnakeString(List<string> req)
{
//TODO: 构造时间过长
var ret = string.Empty;
req.ForEach(x =>
{
ret += "_" + x.ToLower();
});
return ret.Substring(1);
}
#endregion handle
/// <summary>
/// 构造驼峰结果
/// </summary>
/// <param name="req"></param>
/// <param name="isSmallHump">是否为小驼峰</param>
/// <returns></returns>
private string GenHumpString(List<string> req, bool isSmallHump)
{
string ret = string.Empty;
var array = req.ToArray();
for (var j = 0; j < array.Length; j++)
{
char[] chars = array[j].ToCharArray();
if (j == 0 && isSmallHump) chars[0] = char.ToLower(chars[0]);
else chars[0] = char.ToUpper(chars[0]);
for (int i = 1; i < chars.Length; i++)
{
chars[i] = char.ToLower(chars[i]);
}
ret += new string(chars);
}
return ret;
#region Params
private readonly SqliteHelper _sqlHelper;
private string _translateResp;
public ICommand MouseLeftDownCmd { get; set; }
public ICommand DeactivatedCmd { get; set; }
public ICommand SourceSpeakCmd { get; set; }
public ICommand TargetSpeakCmd { get; set; }
public ICommand TranslateCmd { get; set; }
public ICommand CopyInputCmd { get; set; }
public ICommand CopyResultCmd { get; set; }
public ICommand CopySnakeResultCmd { get; set; }
public ICommand CopySmallHumpResultCmd { get; set; }
public ICommand CopyLargeHumpResultCmd { get; set; }
public ICommand ThemeConvertCmd { get; set; }
public ICommand TopmostCmd { get; set; }
public ICommand EscCmd { get; set; }
public ICommand ExitCmd { get; set; }
public ICommand SelectLangChangedCmd { get; set; }
}
/// <summary>
/// 提取英文
/// view传递至viewmodel
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string GetSubString(string str)
{
Regex regex = new Regex("[a-zA-Z]+");
public MainWindow Mainwin;
MatchCollection mMactchCol = regex.Matches(str);
string strA_Z = string.Empty;
foreach (Match mMatch in mMactchCol)
{
strA_Z += mMatch.Value;
}
return strA_Z;
}
#endregion handle
private static Lazy<MainVM> _instance = new Lazy<MainVM>(() => new MainVM());
public static MainVM Instance => _instance.Value;
#region Params
private string translateResp;
public ICommand TranslateCmd { get; private set; }
public ICommand CopyInputCmd { get; private set; }
public ICommand CopyResultCmd { get; private set; }
public ICommand CopySnakeResultCmd { get; private set; }
public ICommand CopySmallHumpResultCmd { get; private set; }
public ICommand CopyLargeHumpResultCmd { get; private set; }
public ICommand ThemeConvertCmd { get; private set; }
public Hotkeys NHotkeys;
private bool IsTopmost { get; set; }
private const string TopmostTemplateName = "ButtonTemplateTopmost";
private const string UnTopmostTemplateName = "ButtonTemplateUnTopmost";
/// <summary>
/// 全局配置文件
/// </summary>
private ConfigModel _globalConfig;
/// <summary>
/// 识别语种
/// </summary>
private string _IdentifyLanguage;
public string IdentifyLanguage { get => _IdentifyLanguage; set => UpdateProperty(ref _IdentifyLanguage, value); }
private string _identifyLanguage;
public string IdentifyLanguage { get => _identifyLanguage; set => UpdateProperty(ref _identifyLanguage, value); }
/// <summary>
/// 构造蛇形结果
/// </summary>
private string _SnakeRet;
public string SnakeRet { get => _SnakeRet; set => UpdateProperty(ref _SnakeRet, value); }
private string _snakeRet;
public string SnakeRet { get => _snakeRet; set => UpdateProperty(ref _snakeRet, value); }
/// <summary>
/// 构造驼峰结果
/// </summary>
private string _SmallHumpRet;
public string SmallHumpRet { get => _SmallHumpRet; set => UpdateProperty(ref _SmallHumpRet, value); }
private string _smallHumpRet;
public string SmallHumpRet { get => _smallHumpRet; set => UpdateProperty(ref _smallHumpRet, value); }
/// <summary>
/// 构造驼峰结果
/// </summary>
private string _LargeHumpRet;
public string LargeHumpRet { get => _LargeHumpRet; set => UpdateProperty(ref _LargeHumpRet, value); }
private string _largeHumpRet;
public string LargeHumpRet { get => _largeHumpRet; set => UpdateProperty(ref _largeHumpRet, value); }
private string _InputTxt;
public string InputTxt { get => _InputTxt; set => UpdateProperty(ref _InputTxt, value); }
private string _inputTxt;
public string InputTxt { get => _inputTxt; set => UpdateProperty(ref _inputTxt, value); }
private string _OutputTxt;
public string OutputTxt { get => _OutputTxt; set => UpdateProperty(ref _OutputTxt, value); }
private string _outputTxt;
public string OutputTxt { get => _outputTxt; set => UpdateProperty(ref _outputTxt, value); }
private List<string> _InputCombo;
public List<string> InputCombo { get => _InputCombo; set => UpdateProperty(ref _InputCombo, value); }
private List<string> _inputCombo;
public List<string> InputCombo { get => _inputCombo; set => UpdateProperty(ref _inputCombo, value); }
private string _InputComboSelected;
public string InputComboSelected { get => _InputComboSelected; set => UpdateProperty(ref _InputComboSelected, value); }
private string _inputComboSelected;
public string InputComboSelected { get => _inputComboSelected; set => UpdateProperty(ref _inputComboSelected, value); }
private List<string> _OutputCombo;
public List<string> OutputCombo { get => _OutputCombo; set => UpdateProperty(ref _OutputCombo, value); }
private List<string> _outputCombo;
public List<string> OutputCombo { get => _outputCombo; set => UpdateProperty(ref _outputCombo, value); }
private string _OutputComboSelected;
public string OutputComboSelected { get => _OutputComboSelected; set => UpdateProperty(ref _OutputComboSelected, value); }
private string _outputComboSelected;
public string OutputComboSelected { get => _outputComboSelected; set => UpdateProperty(ref _outputComboSelected, value); }
/// <summary>
/// 目标接口
/// </summary>
private List<TranslationInterface> _TranslationInterface = new List<TranslationInterface>
{
new TranslationInterface
{
Name = "zu1k",
Api = "https://deepl.deno.dev/translate"
},
new TranslationInterface
{
Name = "zggsong",
Api = "https://zggsong.cn/tt"
},
new TranslationInterface
{
Name = "local",
Api = "http://127.0.0.1:8000/translate"
}
};
public List<TranslationInterface> TranslationInterface { get => _TranslationInterface; set => UpdateProperty(ref _TranslationInterface, value); }
private TranslationInterface _SelectedTranslationInterface;
public TranslationInterface SelectedTranslationInterface { get => _SelectedTranslationInterface; set => UpdateProperty(ref _SelectedTranslationInterface, value); }
private List<Server> _translationInterface;
public List<Server> TranslationInterface { get => _translationInterface; set => UpdateProperty(ref _translationInterface, value); }
private Server _selectedTranslationInterface;
public Server SelectedTranslationInterface { get => _selectedTranslationInterface; set => UpdateProperty(ref _selectedTranslationInterface, value); }
private static Dictionary<string, LanguageEnum> LanguageEnumDict { get => Util.Util.GetEnumList<LanguageEnum>(); }
private static readonly string _ThemeDark = "pack://application:,,,/STranslate;component/Style/Dark.xaml";
private static readonly string _ThemeDefault = "pack://application:,,,/STranslate;component/Style/Default.xaml";
/// <summary>
/// 语音
/// </summary>
private readonly SpeechSynthesizer _speech = new SpeechSynthesizer();
private const string ThemeDark = "pack://application:,,,/STranslate;component/Style/Dark.xaml";
private const string ThemeDefault = "pack://application:,,,/STranslate;component/Style/Default.xaml";
#endregion Params
}
}

@ -0,0 +1,167 @@
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace STranslate.ViewModel
{
public class ScreenShotVM : BaseVM
{
/// <summary>
/// reference https://github.com/NPCDW/WpfTool
/// </summary>
/// <param name="ui"></param>
public ScreenShotVM(Window ui)
{
_ScreenShotWin = ui;
EscCmd = new RelayCommand((_) => true, (_) =>
{
_ScreenShotWin.Close();
});
//鼠标移动
MouseMoveCmd = new RelayCommand((_) => true, (_) =>
{
if (MouseDown)
{
System.Windows.Point CurrentPoint = Mouse.GetPosition(_ScreenShotWin);
Rectangle = new Rect(StartPoint, CurrentPoint);
Canvas.SetLeft(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle, 0);
Canvas.SetTop(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle, 0);
(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle).Width = Rectangle.X;
(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle).Height = bitmap.Height;
Canvas.SetLeft(_ScreenShotWin.FindName("RightMask") as System.Windows.Shapes.Rectangle, Rectangle.Left + Rectangle.Width);
Canvas.SetTop(_ScreenShotWin.FindName("RightMask") as System.Windows.Shapes.Rectangle, 0);
(_ScreenShotWin.FindName("RightMask") as System.Windows.Shapes.Rectangle).Width = bitmap.Width - Rectangle.Left - Rectangle.Width;
(_ScreenShotWin.FindName("RightMask") as System.Windows.Shapes.Rectangle).Height = bitmap.Height;
Canvas.SetLeft(_ScreenShotWin.FindName("UpMask") as System.Windows.Shapes.Rectangle, Rectangle.Left);
Canvas.SetTop(_ScreenShotWin.FindName("UpMask") as System.Windows.Shapes.Rectangle, 0);
(_ScreenShotWin.FindName("UpMask") as System.Windows.Shapes.Rectangle).Width = Rectangle.Width;
(_ScreenShotWin.FindName("UpMask") as System.Windows.Shapes.Rectangle).Height = Rectangle.Y;
Canvas.SetLeft(_ScreenShotWin.FindName("DownMask") as System.Windows.Shapes.Rectangle, Rectangle.Left);
Canvas.SetTop(_ScreenShotWin.FindName("DownMask") as System.Windows.Shapes.Rectangle, Rectangle.Y + Rectangle.Height);
(_ScreenShotWin.FindName("DownMask") as System.Windows.Shapes.Rectangle).Width = Rectangle.Width;
(_ScreenShotWin.FindName("DownMask") as System.Windows.Shapes.Rectangle).Height = bitmap.Height - Rectangle.Height - Rectangle.Y;
}
});
//左键Down
MouseLeftDownCmd = new RelayCommand((_) => true, (_) =>
{
MouseDown = true;
StartPoint = Mouse.GetPosition(_ScreenShotWin);
});
//左键Up
MouseLeftUpCmd = new RelayCommand((_) => true, (_) =>
{
MouseDown = false;
int x = (int)(Rectangle.X * dpiScale);
int y = (int)(Rectangle.Y * dpiScale);
int width = (int)(Rectangle.Width * dpiScale);
int height = (int)(Rectangle.Height * dpiScale);
if (width <= 0 || height <= 0)
{
return;
}
Bitmap bmpOut = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmpOut);
g.DrawImage(bitmap,
new Rectangle(0, 0, width, height),
new Rectangle(x, y, width, height),
GraphicsUnit.Pixel);
_ScreenShotWin.Close();
//TestSaveBmp(bmpOut);
var getText = Util.Util.TesseractGetText(bmpOut).Trim();
MainVM.Instance.ScreenShotTranslateEx(getText);
});
ClosedCmd = new RelayCommand((_) => true, (_) =>
{
Util.Util.FlushMemory();
});
}
/// <summary>
/// 测试保存
/// </summary>
/// <param name="bmp"></param>
private void TestSaveBmp(Bitmap bmp)
{
bmp.Save("D:\\a.png", System.Drawing.Imaging.ImageFormat.Bmp);
}
public Tuple<Rect, int, int, int, int> InitView1()
{
// 获取鼠标所在屏幕
System.Drawing.Point ms = System.Windows.Forms.Control.MousePosition;
Rect bounds = new Rect();
int x = 0, y = 0, width = 0, height = 0;
foreach (WpfScreenHelper.Screen screen in WpfScreenHelper.Screen.AllScreens)
{
bounds = screen.WpfBounds;
dpiScale = screen.ScaleFactor;
x = (int)(bounds.X * dpiScale);
y = (int)(bounds.Y * dpiScale);
width = (int)(bounds.Width * dpiScale);
height = (int)(bounds.Height * dpiScale);
if (x <= ms.X && ms.X < x + width && y <= ms.Y && ms.Y < y + height)
{
break;
}
}
return new Tuple<Rect, int, int, int, int>(bounds, x, y, width, height);
}
public void InitView2(Tuple<Rect, int, int, int, int> tuple)
{
// 设置窗体位置、大小实际宽高单位unit
_ScreenShotWin.Top = tuple.Item1.X;
_ScreenShotWin.Left = tuple.Item1.Y;
_ScreenShotWin.Width = tuple.Item1.Width;
_ScreenShotWin.Height = tuple.Item1.Height;
// 设置遮罩
Canvas.SetLeft(_ScreenShotWin, tuple.Item1.X);
Canvas.SetTop(_ScreenShotWin, tuple.Item1.Y);
(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle).Width = tuple.Item1.Width;
(_ScreenShotWin.FindName("LeftMask") as System.Windows.Shapes.Rectangle).Height = tuple.Item1.Height;
// 设置窗体背景像素宽高单位px
bitmap = new Bitmap(tuple.Item4, tuple.Item5);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(tuple.Item2, tuple.Item3, 0, 0, new System.Drawing.Size(tuple.Item4, tuple.Item5), CopyPixelOperation.SourceCopy);
}
_ScreenShotWin.Background = Util.Util.BitmapToImageBrush(bitmap);
}
public ICommand EscCmd { get; private set; }
public ICommand MouseMoveCmd { get; private set; }
public ICommand MouseLeftDownCmd { get; private set; }
public ICommand MouseLeftUpCmd { get; private set; }
public ICommand ClosedCmd { get; private set; }
private Window _ScreenShotWin; //Window
private Rect Rectangle = new Rect(); //保存的矩形
private System.Windows.Point StartPoint; //鼠标按下的点
private bool MouseDown; //鼠标是否被按下
private Bitmap bitmap; // 截屏图片
private double dpiScale = 1;
}
}

@ -0,0 +1,147 @@
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace STranslate.ViewModel
{
public class SettingsVM : BaseVM
{
public SettingsVM()
{
IsStartup = ShortcutHelper.IsStartup();
Version = HandleVersion(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() ?? "1.0.0.0");
ClosedCmd = new RelayCommand((_) => true, (_) =>
{
Util.Util.FlushMemory();
});
//更新
UpdateCmd = new RelayCommand((_) => true, (_) =>
{
try
{
var updaterExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"Updater.exe");
var updaterCacheExePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Updater",
"Updater.exe");
var updateDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater");
if (!Directory.Exists(updateDirPath))
{
Directory.CreateDirectory(updateDirPath);
}
if (!File.Exists(updaterExePath))
{
MessageBox.Show("升级程序似乎已被删除,请手动前往发布页查看新版本");
return;
}
File.Copy(updaterExePath, updaterCacheExePath, true);
File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Newtonsoft.Json.dll"), Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Updater",
"Newtonsoft.Json.dll"), true);
ProcessHelper.Run(updaterCacheExePath, new string[] { Version });
}
catch (Exception ex)
{
MessageBox.Show($"无法正确启动检查更新程序\n{ex.Message}");
}
});
StartupCmd = new RelayCommand((_) => true, (_) =>
{
if (ShortcutHelper.IsStartup()) ShortcutHelper.UnSetStartup();
else ShortcutHelper.SetStartup();
IsStartup = ShortcutHelper.IsStartup();
});
EscCmd = new RelayCommand((_) => true, (o) =>
{
(o as Window)?.Close();
});
OpenUrlCmd = new RelayCommand((_) => true, (o) =>
{
try
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = o.ToString();
proc.Start();
}
catch (Exception ex)
{
MessageBox.Show($"未找到默认应用\n{ex.Message}");
}
});
}
/// <summary>
/// 同步Github版本命名
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
private static string HandleVersion(string version)
{
var ret = string.Empty;
ret = version.Substring(0, version.Length - 2);
var location = ret.LastIndexOf('.');
ret = ret.Remove(location, 1);
return ret;
}
public ICommand ClosedCmd { get; private set; }
public ICommand OpenUrlCmd { get; private set; }
public ICommand UpdateCmd { get; private set; }
public ICommand StartupCmd { get; private set; }
public ICommand EscCmd { get; private set; }
private static Lazy<SettingsVM> _instance = new Lazy<SettingsVM>(() => new SettingsVM());
public static SettingsVM Instance => _instance.Value;
/// <summary>
/// 是否开机自启
/// </summary>
private bool _isStartup;
public bool IsStartup { get => _isStartup; set => UpdateProperty(ref _isStartup, value); }
/// <summary>
/// 版本
/// </summary>
private string _version;
public string Version { get => _version; set => UpdateProperty(ref _version, value); }
/// <summary>
/// 语种识别比例
/// </summary>
private double _autoScale;
public double AutoScale { get => _autoScale; set => UpdateProperty(ref _autoScale, value); }
/// <summary>
/// 取词间隔
/// </summary>
private double _wordPickupInterval;
public double WordPickupInterval { get => _wordPickupInterval; set => UpdateProperty(ref _wordPickupInterval, value); }
/// <summary>
/// 最大历史记录数量
/// </summary>
private int _maxHistoryCount;
public int MaxHistoryCount { get => _maxHistoryCount; set => UpdateProperty(ref _maxHistoryCount, value); }
}
}

@ -1,4 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.39" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net48" />
<package id="sqlite-net-pcl" version="1.8.116" targetFramework="net48" />
<package id="SQLitePCLRaw.bundle_green" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.core" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.4" targetFramework="net48" />
<package id="System.Buffers" version="4.4.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.3" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
<package id="Tesseract" version="5.2.0" targetFramework="net48" />
<package id="WpfScreenHelper" version="2.1.0" targetFramework="net48" />
</packages>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
</configuration>

@ -0,0 +1,9 @@
<Application x:Class="Updater.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Updater"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Updater
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
private System.Threading.Mutex mutex;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// 阻止多开和用户主动启动
if (e.Args.Length == 0 || IsRuned())
{
Shutdown();
}
Activated += (s, e2) =>
{
var mainWindow = App.Current.MainWindow;
if (mainWindow.DataContext != null)
{
var mainViewModel = mainWindow.DataContext as MainViewModel;
if (string.IsNullOrEmpty(mainViewModel.Version))
{
mainViewModel.Version = e.Args[0];
}
}
};
}
#region 获取当前程序是否已运行
/// <summary>
/// 获取当前程序是否已运行
/// </summary>
private bool IsRuned()
{
bool ret;
mutex = new System.Threading.Mutex(true, System.Reflection.Assembly.GetEntryAssembly().ManifestModule.Name, out ret);
if (!ret)
{
return true;
}
return false;
}
#endregion
}
}

@ -0,0 +1,111 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Updater
{
public class GithubRelease
{
public class VersionInfo
{
/// <summary>
/// 版本标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 版本号
/// </summary>
public string Version { get; set; }
/// <summary>
/// 是否是预览版本
/// </summary>
public bool IsPre { get; set; }
/// <summary>
/// 下载路径
/// </summary>
public string DownloadUrl { get; set; }
/// <summary>
/// 版本更新内容网页链接
/// </summary>
public string HtmlUrl { get; set; }
}
public class GithubModel
{
public string tag_name { get; set; }
public string html_url { get; set; }
public string name { get; set; }
public bool prerelease { get; set; }
public List<GithubAssetsModel> assets { get; set; }
}
public class GithubAssetsModel
{
public string browser_download_url { get; set; }
}
private string githubUrl;
private string nowVersion;
public VersionInfo Info { get; set; }
//public event UpdaterEventHandler RequestCompleteEvent;
//public event UpdaterEventHandler RequestErrorEvent;
//public delegate void UpdaterEventHandler(object sender, object value);
public GithubRelease(string githubUrl, string nowVersion)
{
this.githubUrl = githubUrl;
this.nowVersion = nowVersion;
Info = new VersionInfo();
}
public bool IsCanUpdate()
{
return !(nowVersion == Info.Version);
}
public async Task<VersionInfo> GetRequest()
{
var result = await Task.Run(() =>
{
HttpWebResponse httpWebRespones = null;
try
{
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest httpWebRequest = WebRequest.Create(githubUrl) as HttpWebRequest;
httpWebRequest.Timeout = 60 * 1000;
httpWebRequest.ReadWriteTimeout = 60000;
httpWebRequest.AllowAutoRedirect = true;
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36";
httpWebRespones = (HttpWebResponse)httpWebRequest.GetResponse();
using (Stream stream = httpWebRespones.GetResponseStream())
{
List<byte> lst = new List<byte>();
int nRead = 0;
while ((nRead = stream.ReadByte()) != -1) lst.Add((byte)nRead);
byte[] bodyBytes = lst.ToArray();
string body = Encoding.UTF8.GetString(bodyBytes, 0, bodyBytes.Length);
var data = JsonConvert.DeserializeObject<GithubModel>(body);
Info.IsPre = data.prerelease;
Info.Title = data.name;
Info.Version = data.tag_name;
Info.DownloadUrl = data.assets[0].browser_download_url;
Info.HtmlUrl = data.html_url;
return Info;
}
}
catch (Exception)
{
return null;
}
});
return result;
}
}
}

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Updater
{
public class MainViewModel : INotifyPropertyChanged
{
private double _processValue;
public double ProcessValue { get => _processValue; set => UpdateProperty(ref _processValue, value); }
private string _version;
public string Version { get => _version; set => UpdateProperty(ref _version, value); }
#region notifychanged
public event PropertyChangedEventHandler PropertyChanged;
protected void UpdateProperty<T>(ref T properValue, T newValue, [CallerMemberName] string properName = "")
{
if (object.Equals(properValue, newValue))
return;
properValue = newValue;
NotifyPropertyChanged(properName);
}
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

@ -0,0 +1,57 @@
<Window x:Class="Updater.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Updater"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Icon="update.ico"
Title="STranslate 升级程序" ResizeMode="NoResize" Height="300" Width="420">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel>
<Border Background="#f3f3f3" Padding="10" CornerRadius="2">
<TextBlock x:Name="StatusLabel" Foreground="Gray" TextWrapping="WrapWithOverflow"/>
</Border>
<ProgressBar x:Name="ProgressBar" Height="10" Margin="0,10,0,10" Maximum="100"
Value="{Binding ProcessValue}"/>
<StackPanel x:Name="NewVersionSP" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">
<Run>版本号</Run>
<Run x:Name="Version" Foreground="Gray"/>
</TextBlock>
<Border x:Name="PreTag"
ToolTip="预览版表示开发者没有进行过多的测试相较于正式版可能会多一些bug但也并不是一定"
Background="OrangeRed"
Padding="5,2"
CornerRadius="4"
VerticalAlignment="Center"
Margin="10,0,0,0">
<TextBlock Text="预览版" Foreground="White" FontSize="10" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</StackPanel>
<TextBlock Margin="0,10,0,0" ToolTip="版本简介"><Run x:Name="VersionTitle" Foreground="Gray"/></TextBlock>
<TextBlock Margin="0,10,0,0" ToolTip="在浏览器中打开"><Hyperlink Click="Hyperlink_Click">查看详细更新内容</Hyperlink></TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left">
<Button x:Name="UpdateBtn" Padding="10,8" Margin="0,0,10,0" Click="UpdateBtn_Click">升级到此新版本</Button>
<Button x:Name="ReCheckBtn" Padding="10,8" Click="ReCheckBtn_Click">重新检查</Button>
</StackPanel>
<TextBlock Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Run>当前版本号:</Run><Run Text="{Binding Version}"/>
</TextBlock>
</Grid>
</Window>

@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Updater
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
GithubRelease githubRelease;
/// <summary>
/// 新版本保存目录路径
/// </summary>
private string SaveDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
/// <summary>
/// 新版本保存名字
/// </summary>
private string SaveName = "update.zip";
/// <summary>
/// 新版本下载路径
/// </summary>
private string NewVersionZipURL;
/// <summary>
/// 新版本发布页路径
/// </summary>
private string NewVersionURL;
private MainViewModel _mainViewModel;
public MainWindow()
{
InitializeComponent();
_mainViewModel = new MainViewModel();
DataContext = _mainViewModel;
_mainViewModel.PropertyChanged += MainViewModel_PropertyChanged;
}
private void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(_mainViewModel.Version))
{
githubRelease = new GithubRelease("https://api.github.com/repos/zggsong/stranslate/releases/latest", _mainViewModel.Version);
Check();
}
}
private async void Download()
{
SetStatus("正在下载新版本文件...", false);
UpdateBtn.Visibility = Visibility.Collapsed;
ReCheckBtn.Visibility = Visibility.Collapsed;
ProgressBar.Visibility = Visibility.Visible;
_mainViewModel.ProcessValue = 0;
var res = await Task.Run(() =>
{
try
{
// 确认保存目录
if (!Directory.Exists(SaveDir))
{
Directory.CreateDirectory(SaveDir);
}
Uri uri = new Uri(NewVersionZipURL);
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Timeout = 120 * 1000;
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
long totalBytes = httpWebResponse.ContentLength;
Stream st = httpWebResponse.GetResponseStream();
Stream so = new FileStream(System.IO.Path.Combine(SaveDir, SaveName), FileMode.Create);
long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize + totalDownloadedByte;
so.Write(by, 0, osize);
osize = st.Read(by, 0, (int)by.Length);
//进度计算
double process = double.Parse(String.Format("{0:F}",
((double)totalDownloadedByte / (double)totalBytes * 100)));
_mainViewModel.ProcessValue = process;
//Debug.WriteLine(ProcessValue);
}
//关闭资源
httpWebResponse.Close();
so.Close();
st.Close();
return true;
}
catch (Exception)
{
return false;
}
});
if (res)
{
// 准备更新
var process = Process.GetProcessesByName("STranslate");
if (process != null && process.Length > 0)
{
process[0].Kill();
}
SetStatus("下载完成,正在解压请勿关闭此窗口...");
string unpath = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.FullName;
var unresult = await Task.Run(async () =>
{
await Task.Delay(3000);
return Unzip.ExtractZipFile(System.IO.Path.Combine(SaveDir, SaveName), unpath);
});
if (unresult)
{
SetStatus("更新完成!", false);
Process p = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(System.IO.Path.Combine(unpath, "STranslate.exe"));
p.StartInfo = startInfo;
p.Start();
}
else
{
SetStatus("解压文件时发生异常,请重试!通常情况可能是因为 STranslate 主程序尚未退出。", false);
UpdateBtn.Visibility = Visibility.Visible;
}
}
else
{
//下载发生异常
SetStatus("下载时发生异常,请重试。", false);
UpdateBtn.Visibility = Visibility.Visible;
}
}
private async void Check()
{
NewVersionSP.Visibility = Visibility.Collapsed;
PreTag.Visibility = Visibility.Collapsed;
SetStatus("正在检查更新");
UpdateBtn.Visibility = Visibility.Collapsed;
ReCheckBtn.IsEnabled = false;
var info = await githubRelease.GetRequest();
if (info != null)
{
if (githubRelease.IsCanUpdate())
{
UpdateBtn.Visibility = Visibility.Visible;
NewVersionSP.Visibility = Visibility.Visible;
Version.Text = info.Version;
VersionTitle.Text = info.Title;
NewVersionZipURL = info.DownloadUrl;
NewVersionURL = info.HtmlUrl;
if (info.IsPre)
{
PreTag.Visibility = Visibility.Visible;
}
SetStatus("检测到新的版本!", false);
}
else
{
SetStatus("目前没有可用的更新。", false);
}
}
else
{
SetStatus("无法获取版本信息,请检查代理或网络。", false);
}
ReCheckBtn.IsEnabled = true;
}
private void SetStatus(string statusText, bool isLoading = true)
{
StatusLabel.Text = statusText;
ProgressBar.IsIndeterminate = isLoading;
if (isLoading)
{
ProgressBar.Visibility = Visibility.Visible;
}
else
{
ProgressBar.Visibility = Visibility.Collapsed;
}
}
private void ReCheckBtn_Click(object sender, RoutedEventArgs e)
{
Check();
}
private void UpdateBtn_Click(object sender, RoutedEventArgs e)
{
Download();
}
private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
Process.Start(new ProcessStartInfo(NewVersionURL));
}
}
}

@ -0,0 +1,56 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Updater")]
[assembly: AssemblyDescription("A ready to use and ready to go translation tool")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ZGGSONG")]
[assembly: AssemblyProduct("Updater")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("ZGGSONG")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Guid("54EA0FD9-3908-4A27-8AF7-B98EDCE7804E")]

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Updater.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Updater.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Updater.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

@ -0,0 +1,85 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace Updater
{
public class Unzip
{
/// <summary>
/// 忽略的文件列表
/// </summary>
static readonly string[] IgnoreFiles = { };
public static bool ExtractZipFile(string zipPath, string extractPath)
{
try
{
if (!extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
extractPath += Path.DirectorySeparatorChar;
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (!IsIgnoreFile(entry.FullName))
{
// Gets the full path to ensure that relative segments are removed.
string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));
if (!IsDir(destinationPath))
{
// 判断路径是否存在
string dir = Path.GetDirectoryName(destinationPath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (File.Exists(destinationPath))
{
File.Delete(destinationPath);
}
// Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
// are case-insensitive.
Debug.WriteLine($"抽取:{destinationPath}");
if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal))
entry.ExtractToFile(destinationPath);
}
else
{
//创建目录
Directory.CreateDirectory(destinationPath);
}
}
}
return true;
}
}
catch
{
return false;
}
}
/// <summary>
/// 指示文件是否是忽略的
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
static bool IsIgnoreFile(string fileName)
{
return (Array.IndexOf(IgnoreFiles, fileName) != -1);
}
/// <summary>
/// 指示路径是否是目录
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
static bool IsDir(string path)
{
return path.Last() == '\\';
}
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A49C9514-81CA-4FB6-A586-17477E4F28A8}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Updater</RootNamespace>
<AssemblyName>Updater</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>
    <!-- 阻止默认的 XML 和 PDB 文件复制到 RELEASE 的输出目录. 只有*.allowedextension 扩展名的文件可以被包含, 当然这个扩展的文件并不存在.-->
    .allowedextension
  </AllowedReferenceRelatedFileExtensions>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>update.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Unzip.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="GithubRelease.cs" />
<Compile Include="MainViewModel.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="update.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net48" />
</packages>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 618 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Loading…
Cancel
Save