WPF 使用快捷键方式制作简易的 Word 上的 Latex 输入法

news/2024/10/24 7:14:13

软件的界面效果如下:

运行效果如下:

本文以下为演示应用,没有包含从用户输入生成 Latex 格式的公式,仅仅只包含核心的如何在 Word 插入公式部分

本文的核心实现逻辑是根据 WPF 拼音输入法 实现的,只是有所不同的是没有进行键盘钩子,而是代替为手动点击按钮

点击发送按钮将 Latex 公式输入到 Word 里作为 Word 公式,其核心的方法就是使用 Word 的快捷键插入公式编辑器,再通过剪贴板输入 Latex 格式的公式内容,再输入回车作为 Word 公式。按钮的点击的实现代码如下

    private void SendButton_OnClick(object sender, RoutedEventArgs e){SendKeys.SendWait("%="); // 发送 alt+= 让Word打开公式编辑器Clipboard.SetText("a^2+b^2=c^2"); // 将文本放入剪贴板SendKeys.SendWait("^v"); // 发送 ctrl+v 粘贴文本SendKeys.SendWait("{Enter}"); // 发送回车键让 Latex 公式成为 Word 公式}

上文这里固定发送的是 a^2+b^2=c^2 公式,大家可以根据需求自行替换为其他公式

以下为整个项目的详细实现方法

先创建一个 .NET 9 的 WPF 项目,创建之后记得勾选 WinForms 引用,如不知道在哪勾选,可以双击项目文件,将 csproj 项目文件替换为如下代码

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>WinExe</OutputType><TargetFramework>net9.0-windows</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><UseWindowsForms>True</UseWindowsForms><UseWPF>true</UseWPF></PropertyGroup></Project>

以上代码里面的 <UseWindowsForms>True</UseWindowsForms> 就是用来添加对 WinForms 的引用。如果大家看了以上配置还是不知道如何做,可以在本文末尾找到本文所有代码的下载方法

接着打开 MainWindow.xaml 文件,写一个固定且简单的输入法界面

    <Grid><TextBlock HorizontalAlignment="Left" VerticalAlignment="Top"FontSize="20"><Run Foreground="Gray" Text="1."/><Run Foreground="Black" Text="a^2+b^2=c^2"></Run></TextBlock><Button x:Name="SendButton"Margin="10 10 10 10"HorizontalAlignment="Right" VerticalAlignment="Bottom"Click="SendButton_OnClick">发送</Button></Grid>

以上界面固定了一个输入法候选公式,和一个按钮

继续编辑 MainWindow.xaml 文件,设置一些窗口属性

        WindowStyle="ToolWindow"Topmost="True"Title="Latex Word 输入法" Height="100" Width="300"

按钮点击的 SendButton_OnClick 方法的实现已经在上文告诉大家

作为一个输入法,不应该让窗口获取焦点,否则将会抢走应用的焦点。按照 .NET/C# 使窗口永不激活(No Activate 永不获得焦点) - walterlv 博客提供的方法,在 MainWindow.xaml.cs 配置让窗口不获取焦点

    protected override void OnSourceInitialized(EventArgs e){base.OnSourceInitialized(e);var windowInteropHelper = new WindowInteropHelper(this);Win32WindowHelper.SetNoActivate(windowInteropHelper.Handle);}public static class Win32WindowHelper
{/// <summary>/// 使窗口永不激活/// </summary>/// <param name="hWnd"></param>/// [.NET/C# 使窗口永不激活(No Activate 永不获得焦点) - walterlv](https://blog.walterlv.com/post/no-activate-window.html )public static void SetNoActivate(IntPtr hWnd){var exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);SetWindowLong(hWnd, GWL_EXSTYLE, new IntPtr(exStyle.ToInt32() | WS_EX_NOACTIVATE));}private const int WS_EX_NOACTIVATE = 0x08000000;private const int GWL_EXSTYLE = -20;public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex){return Environment.Is64BitProcess? GetWindowLong64(hWnd, nIndex): GetWindowLong32(hWnd, nIndex);}public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong){return Environment.Is64BitProcess? SetWindowLong64(hWnd, nIndex, dwNewLong): SetWindowLong32(hWnd, nIndex, dwNewLong);}[DllImport("user32.dll", EntryPoint = "GetWindowLong")]private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]private static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);[DllImport("user32.dll", EntryPoint = "SetWindowLong")]private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]private static extern IntPtr SetWindowLong64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
}

整个 MainWindow.xaml.cs 的核心代码如下

public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();}protected override void OnSourceInitialized(EventArgs e){base.OnSourceInitialized(e);var windowInteropHelper = new WindowInteropHelper(this);Win32WindowHelper.SetNoActivate(windowInteropHelper.Handle);}private void SendButton_OnClick(object sender, RoutedEventArgs e){SendKeys.SendWait("%="); // 发送 alt+= 让Word打开公式编辑器Clipboard.SetText("a^2+b^2=c^2"); // 将文本放入剪贴板SendKeys.SendWait("^v"); // 发送 ctrl+v 粘贴文本SendKeys.SendWait("{Enter}"); // 发送回车键让 Latex 公式成为 Word 公式}
}public static class Win32WindowHelper
{/// <summary>/// 使窗口永不激活/// </summary>/// <param name="hWnd"></param>/// [.NET/C# 使窗口永不激活(No Activate 永不获得焦点) - walterlv](https://blog.walterlv.com/post/no-activate-window.html )public static void SetNoActivate(IntPtr hWnd){var exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);SetWindowLong(hWnd, GWL_EXSTYLE, new IntPtr(exStyle.ToInt32() | WS_EX_NOACTIVATE));}private const int WS_EX_NOACTIVATE = 0x08000000;private const int GWL_EXSTYLE = -20;public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex){return Environment.Is64BitProcess? GetWindowLong64(hWnd, nIndex): GetWindowLong32(hWnd, nIndex);}public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong){return Environment.Is64BitProcess? SetWindowLong64(hWnd, nIndex, dwNewLong): SetWindowLong32(hWnd, nIndex, dwNewLong);}[DllImport("user32.dll", EntryPoint = "GetWindowLong")]private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]private static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);[DllImport("user32.dll", EntryPoint = "SetWindowLong")]private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]private static extern IntPtr SetWindowLong64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
}

本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 18e21d7acfd12a55b04f554cbe5ce770e37518ef

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 18e21d7acfd12a55b04f554cbe5ce770e37518ef

获取代码之后,进入 WPFDemo/QarchananaFeweajeka 文件夹,即可获取到源代码

打开 QarchananaFeweajeka.sln 文件,理论上就可以按下 F5 让 VisualStudio 构建且运行。试试新建一个 Word 文档,进入输入状态,然后点击运行起来的输入法程序的发送按钮。预计就可以看到在 Word 输入了一段公式

更多技术博客,请参阅 博客导航

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/75321.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

读数据工程之道:设计和构建健壮的数据系统18数据存储系统(上)

数据存储系统(上)1. 单机存储和分布式存储 1.1. 存储系统是存在于原材料之上的抽象层次 1.2. 磁盘是一种原始存储材料,而主要的云对象存储平台和HDFS是利用磁盘的存储系统 1.3. 随着数据存储和访问模式变得越来越复杂,并超出了单一服务器能做到的支持,将数据分布到一个以上…

2024.10.24 鲜花

多次查询给定集合是否存在任一给定子集多次查询给定集合是否存在任一给定子集Re:End of a Dream给定 \(n\) 个集合 \(S_n\) ,\(q\) 组询问,每次给定一个集合 \(Q\),判断其是否包含一个集合 \(S_i\)。先考虑经典例题 DZY Loves Chinese II 考虑其做法:随机赋值非树边,用返…

指令

带v-的特殊属性即为指令,常见的指令有v-if,v-show,v-html,v-text,v-slot,v-bind,v-on,v-model等等,也可自定义指令。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。除了name为必须外,其他的都可以没有,也可以有,修饰符可以有多个; v-focus v-aa.bb v-aa:aa.b…

温故知新,基于播客形式学习英语之EnglishPod 365, Elementary初级C集合(音频、原文、讲解)

简介 Enishpod是一家公司叫做Praxis Language推出的收费讲座,相比较ESLPod, EnishPod为常速。Enishpod极具趣味性,两位主持人Marco和Amira的讲解很生动幽默,完全有别于新概念类型听力的乏味。同时,Enishpod分了不同的难度级别,基础较差可以先选择B级和C级。 Elementary - …

网课视频课程下载神器,学无止下载器,快过期的课程有救了!

有多少小伙伴像我一样,准备在假期好好学点兴趣以内的东西,结果发现花费好几百块买的课居然过期了打开之后课程已经过期,无法观看了(网易云课堂购买的课程过期后无法观看了。。。)又想学习,又不想再浪费钱,该怎么办呢?一顿操作猛如虎,费了半天功夫装了X猴,装了各种插件…

手把手教你如何下载智慧职教(职教云)视频课程课件资料

前言:很多同学都想知道智慧职教(职教云)中课程视频资料怎么下载,但是智慧职教中某个课程的目录中展示的视频和资料是不提供直接下载方式的,所以下面就教大家如何用学无止下载器下载目录中展示的视频资料,包括MP4,PPT和PDF。 一、电脑登录智慧职教网页版 网页版智智慧职教…

手把手教你如何下载知到智慧树视频课程课件资料

前言:很多同学都想知道知到智慧树课程中的课件资料怎么下载,但是知到智慧树中某个课程的目录中展示的课件有时候是不提供直接下载方式的,所以下面就教大家如何下载知到智慧树目录中展示的视频和课件资料,包括PPT和PDF。 提示:操作需要用到Windows电脑,Mac还不支持 一、电…

手把手教你如何下载超星学习通视频课程课件资料

前言:很多同学都想知道超星学习通中课程资料怎么下载,但是超星学习通中某个课程的目录中展示的资料是不提供直接下载方式的,所以下面就教大家如何下载超星学习通目录中展示的视频课件资料,包括PPT和PDF。 一、电脑登录超星学习通网页版,复制课程链接【https://i.chaoxing.…