Python微信訂餐小程序課程視頻
https://edu.csdn.net/course/detail/36074
Python實(shí)戰(zhàn)量化交易理財(cái)系統(tǒng)
https://edu.csdn.net/course/detail/35475
本文告訴大家在 WPF 寫一個(gè)自定義的文本框,如何實(shí)現(xiàn)讓輸入法跟隨光標(biāo)
本文非小白向,本文適合想開(kāi)發(fā)自定義的文本框,從底層開(kāi)始開(kāi)發(fā)的文本庫(kù)的伙伴。在開(kāi)始之前,期望了解了文本庫(kù)開(kāi)發(fā)的基礎(chǔ)知識(shí)
本文實(shí)現(xiàn)的效果如下
實(shí)現(xiàn)
本文的方法參考了 WPF 官方倉(cāng)庫(kù)的邏輯,可以在 WPF 倉(cāng)庫(kù)的 wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\System\Windows\Documents\ImmComposition.cs
文件看到官方是如何讓 TextBox 控件獲取輸入法焦點(diǎn),和在輸入光標(biāo)變更時(shí),修改輸入法的輸入框坐標(biāo)
先了解一下輸入法的相關(guān)知識(shí)。在 Windows 編程開(kāi)發(fā)里,輸入法框架有三套,其中用的最多的是第二套。第二套是采用 IMM 進(jìn)行對(duì)接的。所謂 IMM 就是 Input Method Manager 也就是 輸入法管理器
相關(guān)的另一個(gè)縮寫詞 IME 則是 Input Method Editor 或者是 Input Method Engine 的縮寫,含義是輸入法編輯器或輸入法引擎
應(yīng)用程序可以通過(guò) IMM 對(duì)接輸入法。所用的 win32 的 API 重點(diǎn)是如下幾個(gè)
- ImmGetContext 獲取輸入法上下文,用于后續(xù)所有的其他函數(shù)調(diào)用
- ImmAssociateContext 關(guān)聯(lián)輸入法和對(duì)應(yīng)的窗口,讓輸入法了解在哪個(gè)窗口輸入
- ImmSetCompositionWindow 用來(lái)設(shè)置輸入法的窗口的坐標(biāo),也是本文最重要的函數(shù)
本文接下來(lái)將告訴大家如何一步步實(shí)現(xiàn)封裝對(duì) IME 輸入法調(diào)用,在本文最后將會(huì)給出所有的源代碼
這部分對(duì)輸入法的邏輯可以封裝為一個(gè)類,這樣上層就可以不關(guān)注細(xì)節(jié)邏輯。如例子代碼,放在 IMESupporter 類型里
為了方便文本框的接入,咱再定義一個(gè)接口,用于設(shè)置文本框需要實(shí)現(xiàn)一些方法,用來(lái)提供參數(shù)給 IMESupporter 使用才能進(jìn)行接入
///
/// 表示控件支持被輸入法
///
interface IIMETextEditor
{
///
/// 獲取當(dāng)前使用的字體名
///
///
string GetFontFamilyName();
///
/// 獲取字號(hào)大小,單位和 WPF 的 FontSize 相同
///
///
int GetFontSize();
///
/// 獲取輸入框的左上角的點(diǎn),用于設(shè)置輸入法的左上角。此點(diǎn)相對(duì)于 所在元素坐標(biāo)。對(duì)大部分控件來(lái)說(shuō),都應(yīng)該是 0,0 點(diǎn)
///
///
Point GetTextEditorLeftTop();
///
/// 獲取光標(biāo)的輸入左上角的點(diǎn)。此點(diǎn)相對(duì)于 所在元素坐標(biāo)
///
///
Point GetCaretLeftTop();
}
對(duì)于如微軟拼音等輸入法,是支持設(shè)置輸入法的文本大小和字體。因此就需要文本框提供 GetFontFamilyName 和 GetFontSize 方法
而 GetCaretLeftTop 自然就是用來(lái)讓輸入法跟隨的。為了讓文本框可以做更多的定制,也需要 GetTextEditorLeftTop 方法,這個(gè)方法的返回值對(duì)大部分自定義的文本框控件來(lái)說(shuō),都應(yīng)該是 0,0 點(diǎn)
在 IMESupporter 類型構(gòu)造函數(shù),期望傳入文本框控件,如此可以解決初始化值和監(jiān)聽(tīng)的鍋
internal class IMESupporter<T> where T : UIElement, IIMETextEditor
{
// ReSharper disable InconsistentNaming
public IMESupporter(T editor)
{
Editor = editor;
// 忽略代碼
}
}
為了同時(shí)約束傳入的文本框控件繼承 UIElement 和 IIMETextEditor 接口,用了泛形
在文本框控件 Editor 獲取焦點(diǎn)的時(shí)候,將需要喚起輸入法進(jìn)行輸入。在 Editor 失去焦點(diǎn)的時(shí)候,就應(yīng)該告訴輸入法當(dāng)前不進(jìn)行輸入
public IMESupporter(T editor)
{
Editor = editor;
Editor.GotKeyboardFocus += Editor_GotKeyboardFocus;
Editor.LostKeyboardFocus += Editor_LostKeyboardFocus;
}
private T Editor { get; }
根據(jù) WPF 的約定,對(duì)自定義的支持輸入法的控件,需要設(shè)置 IsInputMethodSuspendedProperty 附加屬性,如下面代碼
InputMethod.SetIsInputMethodSuspended(editor, true);
在 Editor_GotKeyboardFocus
需要實(shí)現(xiàn)的邏輯是調(diào)起輸入法和設(shè)置初始的輸入框的坐標(biāo)。如上文,開(kāi)始之前,需要先拿到輸入法上下文。在拿到輸入法上下文之前,可以先獲取默認(rèn)的 IME 類窗口句柄。先獲取默認(rèn)的 IME 類窗口句柄是為了在多進(jìn)程嵌入窗口時(shí),讓微軟拼音輸入法的輸入框跟隨輸入光標(biāo)而不是在左上角文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-442773.html
_defaultImeWnd = IMENative.ImmGetDefaultIMEWnd(IntPtr.Zero);
以上的 _defaultImeWnd
是一個(gè)字段,在 IMESu文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-442773.html
到了這里,關(guān)于WPF 自定義文本框輸入法 IME 跟隨光標(biāo)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!