WPF 自定义文本框输入法 IME 跟随光标

本文介绍了如何在WPF中创建一个自定义文本框,使其能够实现输入法(IME)跟随光标。文章详细讲解了输入法框架、相关API的使用,并提供了实现逻辑和代码示例,帮助开发者从底层开始开发自定义文本框。
摘要由CSDN通过智能技术生成

Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475
本文告诉大家在 WPF 写一个自定义的文本框,如何实现让输入法跟随光标

本文非小白向,本文适合想开发自定义的文本框,从底层开始开发的文本库的伙伴。在开始之前,期望了解了文本库开发的基础知识

本文实现的效果如下

实现

本文的方法参考了 WPF 官方仓库的逻辑,可以在 WPF 仓库的 wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\System\Windows\Documents\ImmComposition.cs 文件看到官方是如何让 TextBox 控件获取输入法焦点,和在输入光标变更时,修改输入法的输入框坐标

先了解一下输入法的相关知识。在 Windows 编程开发里,输入法框架有三套,其中用的最多的是第二套。第二套是采用 IMM 进行对接的。所谓 IMM 就是 Input Method Manager 也就是 输入法管理器

相关的另一个缩写词 IME 则是 Input Method Editor 或者是 Input Method Engine 的缩写,含义是输入法编辑器或输入法引擎

应用程序可以通过 IMM 对接输入法。所用的 win32 的 API 重点是如下几个

  • ImmGetContext 获取输入法上下文,用于后续所有的其他函数调用
  • ImmAssociateContext 关联输入法和对应的窗口,让输入法了解在哪个窗口输入
  • ImmSetCompositionWindow 用来设置输入法的窗口的坐标,也是本文最重要的函数

本文接下来将告诉大家如何一步步实现封装对 IME 输入法调用,在本文最后将会给出所有的源代码

这部分对输入法的逻辑可以封装为一个类,这样上层就可以不关注细节逻辑。如例子代码,放在 IMESupporter 类型里

为了方便文本框的接入,咱再定义一个接口,用于设置文本框需要实现一些方法,用来提供参数给 IMESupporter 使用才能进行接入

    /// 
    /// 表示控件支持被输入法
    /// 
    interface IIMETextEditor
    {
        /// 
        /// 获取当前使用的字体名
        /// 
        /// 
        string GetFontFamilyName();

        /// 
        /// 获取字号大小,单位和 WPF 的 FontSize 相同
        /// 
        /// 
        int GetFontSize();

        /// 
        /// 获取输入框的左上角的点,用于设置输入法的左上角。此点相对于  所在元素坐标。对大部分控件来说,都应该是 0,0 点
        /// 
        /// 
        Point GetTextEditorLeftTop();

        /// 
        /// 获取光标的输入左上角的点。此点相对于  所在元素坐标
        /// 
        /// 
        Point GetCaretLeftTop();
    }

对于如微软拼音等输入法,是支持设置输入法的文本大小和字体。因此就需要文本框提供 GetFontFamilyName 和 GetFontSize 方法

而 GetCaretLeftTop 自然就是用来让输入法跟随的。为了让文本框可以做更多的定制,也需要 GetTextEditorLeftTop 方法,这个方法的返回值对大部分自定义的文本框控件来说,都应该是 0,0 点

在 IMESupporter 类型构造函数,期望传入文本框控件,如此可以解决初始化值和监听的锅

    internal class IMESupporter<T> where T : UIElement, IIMETextEditor
    {
        // ReSharper disable InconsistentNaming
        public IMESupporter(T editor)
        {
            Editor = editor;
            // 忽略代码
        }
    }

为了同时约束传入的文本框控件继承 UIElement 和 IIMETextEditor 接口,用了泛形

在文本框控件 Editor 获取焦点的时候,将需要唤起输入法进行输入。在 Editor 失去焦点的时候,就应该告诉输入法当前不进行输入

        public IMESupporter(T editor)
        {
            Editor = editor;
            Editor.GotKeyboardFocus += Editor_GotKeyboardFocus;
            Editor.LostKeyboardFocus += Editor_LostKeyboardFocus;
        }

        private T Editor { get; }

根据 WPF 的约定,对自定义的支持输入法的控件,需要设置 IsInputMethodSuspendedProperty 附加属性,如下面代码

            InputMethod.SetIsInputMethodSuspended(editor, true);

Editor_GotKeyboardFocus 需要实现的逻辑是调起输入法和设置初始的输入框的坐标。如上文,开始之前,需要先拿到输入法上下文。在拿到输入法上下文之前,可以先获取默认的 IME 类窗口句柄。先获取默认的 IME 类窗口句柄是为了在多进程嵌入窗口时,让微软拼音输入法的输入框跟随输入光标而不是在左上角

            _defaultImeWnd = IMENative.ImmGetDefaultIMEWnd(IntPtr.Zero);

以上的 _defaultImeWnd 是一个字段,在 IMESup

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值