输入法开发日记

2020年7月26日

C++11(及现代C++风格)和快速迭代式开发 – 刘未鹏 | Mind Hacks

《C++ Primer Plus》(第6版)

2020年7月27日

IME输入法编程心得 - FreedomShe - 博客园
https://www.cnblogs.com/freedomshe/archive/2012/11/30/ime_learning.html

“/ZI”和“/Gy-”命令行选项不兼容

解决方案:

  1. 右键项目,打开属性对话框。
  2. 配置属性 > C/C++ > 常规
  3. 调试信息格式改为 程序数据库 (/Zi)
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kiApiCH3-1598702342081)(E:\code\c++\PC平台藏文拉丁转写输入\log_img\image-20200727151851142.png)]

"链接器工具错误 LNK2026 XXX模块对于 SAFESEH 映像是不安全的

解决方法:

1.打开该项目的“属性页”对话框。

2.单击“链接器”文件夹。

3.单击“命令行”属性页。

4.将 /SAFESEH:NO 键入“附加选项”框中,然后点击应用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RWK77pu1-1598702342082)(E:\code\c++\PC平台藏文拉丁转写输入\log_img\image-20200727151936248.png)]

Requirements for IME development (Windows Store apps) - Windows app development | Microsoft Docs
https://docs.microsoft.com/zh-cn/previous-versions/windows/apps/hh967425(v=win.10)

Input Method Manager - Win32 apps | Microsoft Docs
https://docs.microsoft.com/zh-cn/windows/win32/intl/input-method-manager

2020年7月28日

输入法(IME)实现原理_LANSINE_新浪博客
http://blog.sina.com.cn/s/blog_56a388c20100004u.html

Google Code Archive - Long-term storage for Google Code Project Hosting.
https://code.google.com/archive/p/windows-config/wikis/Win32IME.wiki

微软新一代输入法框架 TSF - Text Service Framework 小小的研究_PunCha (PCH)-CSDN博客_tsf框架输入法 https://blog.csdn.net/puncha/article/details/13293665

copyliu/YIME: 一个输入法
https://github.com/copyliu/YIME

2020年7月29日

NyaRuRu/TSF-TypeLib: Type Library of Text Services Framework for .NET
https://github.com/NyaRuRu/TSF-TypeLib

TSF自定义候选词列表界面 - ShengM - 博客园 https://www.cnblogs.com/ShengM/p/5620814.html

输入法的调试方法 | 学步园 https://www.xuebuyuan.com/691828.html

基于文本服务框架的拼音输入法研究与实现_fishmai的专栏-CSDN博客_基于文本服务框架的拼音输入法研究与实现 https://blog.csdn.net/fishmai/article/details/60756753

2020年7月30日

Text Services Framework (Text Services Framework) - Win32 apps | Microsoft Docs
https://docs.microsoft.com/en-us/windows/win32/tsf/text-services-framework

Google Translate
https://translate.google.co.uk/translate?hl=en&sl=ja&tl=zh-CN&u=https%3A%2F%2Fnyaruru.hatenablog.com%2Fentry%2F20070325%2Fp1&prev=search&sandbox=1

2020年8月4日

win10自带的notepad不能用于输入法的调试,会不加载dll,原因未知。使用notepad++可以直接单步进入代码调试。

要开启启动本地代码调试,加载符号。

这里留个效果图。

输入法开发日记_第1张图片

2020年8月10日

容器

以下GUID用于标识预定义语言栏项目。这些数值通过GetItem函数,用来 获取特殊的的语言栏项。

  • GUID_LBI_SAPILAYR_CFGMENUBUTTON
    语音工具栏菜单项。
  • GUID_TFCAT_TIP_HANDWRITING
    手写输入项
  • GUID_TFCAT_TIP_KEYBOARD
    键盘输入项

MSDN

  • GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER
    如果Text Service需要支持显示属性信息(display attribute infomation)需要注册这个容器。
  • GUID_TFCAT_TIPCAP_SECUREMODE
    Text Service 支持安全模式。
  • TF_IPP_CAPS_UIELEMENTENABLED
    Text Service支持UI元素。
  • TF_IPP_CAPS_COMLESSSUPPORT
    Text Service不需要COM也可以激活。
  • TF_IPP_CAPS_WOW16SUPPORT
    Text Service可以在16位的任务上激活。
  • TF_IPP_CAPS_IMMERSIVESUPPORT
    从Win8开始:Text Service已经通过测试,可以正常运行在Windows应用商店程序中。
  • GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT
    从win8开发:Text Service支持在系统托盘中。这个使于那些未设置TF_IPP_CAPS_IMMERSIVESUPPORT标志,但是仍然与系统托盘兼容的Text Service。

2020年8月11日

访问注册表被拒绝

在 项目属性(Properties)上右键,添加=>新建项 选择“应用程序清单文件(仅限Windows)” 然后单击 添加 按钮
添加后,默认打开app.manifest文件,将:

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

修改为:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

重新生成项目。调试运行时就会提示需要以管理员权限运行。

COM接口转换失败

添加[STAThread]在Main上。

MSDN上是这样解释的:
在主入口上应用这个特性(在C#和VB中为Main函数)。在其他方法上应用没有任何效果。为了在你代码中启动的线程中设置单元状态,请在线程开始前调用Thread.SetApartmentState 或者 Thread.TrySetApartmentState

语言支持列表:
[MS-LCID]: Appendix A: Product Behavior | Microsoft Docs
https://docs.microsoft.com/zh-cn/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c

为服务器应用选择 .NET Core 或 .NET Framework | Microsoft Docs
https://docs.microsoft.com/zh-cn/dotnet/standard/choosing-core-framework-server

在 Windows 上安装 .NET Core | Microsoft Docs
https://docs.microsoft.com/zh-cn/dotnet/core/install/windows?tabs=netcore22

.NET Framework 系统要求 | Microsoft Docs
https://docs.microsoft.com/zh-cn/dotnet/framework/get-started/system-requirements

TIP:好像有时候调试的用的编辑器会被玩坏掉,换一款试试看。

2020年8月12日

事件需要在Active内注册监听。
注册服务均可以从ITfThreadMgr中获得。获得到的对象需要使用Marshal.ReleaseComObject函数来释放。
键盘事件需要通过 ITfKeystrokeMgr.AdviseKeyEventSink 注册。
ITfSource.AdviseSink可以注册通知监听。包含:
IID_ITfActiveLanguageProfileNotifySink
IID_ITfDisplayAttributeNotifySink
IID_ITfKeyTraceEventSink
IID_ITfPreservedKeyNotifySink
IID_ITfThreadFocusSink
IID_ITfThreadMgrEventSink

2020年8月14日

输入法算法实现:隐马尔可夫模型、2-Gram的模型、云端3-Gram的语言模型

2020年8月18日

System.Runtime.InteropServices.COMException (0x80040201): 事件无法调用任何订户 (异常来自 HRESULT:0x80040201)
很是疑惑,待解决。

此外系统自带的记事本只触发OnTestKeyDown、OnTestKeyUp这两个函数,而用Typora测试的时候,就只触发OnKeyDown、OnKeyUp这两个函数,暂且不知道这俩对区别。

【更正】2020年8月19日 OnTestKeyDown OnTestKeyUp 下pfEaten返回true,才会调用对应的OnKeyDown。

2020年8月19日

异常转换为ManagerReturnValues 对象以后,显示的错误为TF_E_NOLOCK:The cookie in ec is invalid.

重要】 EditSession 的EditCookie仅仅只在DoEditSession函数体内有效,出了该函数体范围以后,文档将解除锁定,session已经失效且无法再使用。

COM 对象与其基础 RCW 分开后就不能再使用。错误解决

var keystrokeMgr = _threadMgr as ITfKeystrokeMgr;
            if (keystrokeMgr == null)
                return false;

if (!(_threadMgr is ITfKeystrokeMgr keystrokeMgr))
                return false;

等价,且均为同一个实例。不需要使用Marshal.ReleaseComObject(keystrokeMgr);释放,否则会出现System.Runtime.InteropServices.InvalidComObjectException:“COM 对象与其基础 RCW 分开后就不能再使用。”错误。

public HRESULT OnTestKeyDown(ITfContext pic, UIntPtr wParam, IntPtr lParam, out bool pfEaten)传入的ITfContext实例 与 var res = _threadMgr.GetFocus(out var documentMgr);res = documentMgr.GetTop(out var context); 返回context地址一样,均指向同一个实例。

2020年8月20日

候选词引擎分为两部分:拉丁字母输入、候选词列表和用户词典。

  1. 拉丁字母输入:
             每输入一个拉丁字母,就尝试与之前输入的拉丁组成音节,如果组成失败的话,则尝试在这次拉丁字母前加入虚音节点,虚音节点不可被用户手动删除。如果还是存在错误,则进入错误状态。允许拉丁输入,包含错误字母及其以后的输入拉丁字母均为红色且带有双删除符,并且不再更新候选词列表,直到错误解除。此外,用户还自己按下f,输入实音节点,该分隔符可以被用户删除。
            可以按下左右按键移动光标。
            输入长度限制为64个。
            其中,由于大写拉丁字母输入比较麻烦。小写拉丁字母可以同时表示小写和大写拉丁字母。大写拉丁只表示大写拉丁字母。
            拉丁字母输入采用状态机来表示和转移状态。每次输入以后,从最近一个音节点开始检查语法,并尝试添加虚音节点。
  2. 候选词列表:(删除)
            根据字典中每个词的长度,分为64个已排序的数组保存。其中一个音节也算一个词。每次根据输入的拉丁字,从尽可能最长的词查找。如果没有最长的词或者不够一页,则逐级递减音节。查找到的候选词按照词频从高到低排序直到有足够的候选词凑齐一页,然后挂起查询,直到用户翻页或者找到需要的单词时候,就清空状态。
  3. 用户词典:
            当不存在用户字典时候,由系统自带的音节库和词库生成用户字典,音节也算一个词,默认词频均为1。当用户组成新词的时候,加入用户词典;当用户选择旧词的时候,词频尝试+1除非算术溢出。词频采用uint来保存。
            如果已经达到更新时间5s,且没有子线程在写入用户词典,则将用户词典需要更新的内容写入内存缓存,新建一个子线程去做更新磁盘上的用户词典操作。
            用户字典文件为文件头(TID),版本号3.0,文件头长度,64个词指数组指针。
            如果输入法启动的时候,存在备份文件,表示上次写入时候遇到意外关机,则重命名词典文件为.tdb,使用旧词典。
            写入操作方式如下:
            1. 重命名词典文件为.tdb.bak,备份旧词典。
            2. 复制文件。
            3. 写入更新内容。
            4. 成功以后,删除旧词典文件。

2020年8月22日

藏语符号 来源

  • 分音点:་
  • 句间标点:
    单垂符:།
    双垂符:༎
    四垂符:༎༎
    音节点垂符:༏
    双音节点垂符:༐
    伏藏句点:༔
  • 括号:
    左曲符:༺
    右曲符:༻
    左半壁符:༼
    右半壁符:༽
    上玄日符:༾
    下玄日符:༿
  • 省略符:༴
  • 重复符:྾
  • 插入符:྿
    四眼插入符:༶
    铜镜插入符:༓
  • 凸显符号:༷ 或者 ༵
  • 尊敬符:༸
  • 起始提示符:༄

2020年8月26日

感觉之前设计的候选词引擎不太对,这次用暴力实现实现,查询就用LINQ语句暴力查。

2020年8月28日

候选词引擎分为两部分:拉丁字母输入、用户词典。

2020年8月28日 重新设计

  1. 拉丁字母输入器:
             每输入一个字母或者音节点,就从左边最近的音节点开始检查语法。当遇到非拉丁转写的字母或者不能与上一个拉丁组成一个音节的拉丁字母,就尝试插入虚音节点。如果还是存在错误,则进入错误状态。其中输入的实音节点,被用户删除,虚节点表示不存在。
            可以移动光标。
            输入长度限制为64个。
            其中,由于大写拉丁字母输入比较麻烦。小写拉丁字母可以同时表示小写和大写拉丁字母。大写拉丁只表示大写拉丁字母。
            拉丁字母输入采用状态机来表示和转移状态。每次输入以后,从最近一个音节点开始检查语法,并尝试添加虚音节点。
  2. 用户字典:
            当不存在用户字典时候,由系统自带的音节库和词库生成用户字典,音节也算一个词,默认词频均为1。
            根据用户输入的音节输入的音节,查询是否存在同样长度或者更短长度的音节相一致的单词。查询结果按照单词长度(主序)和词频(次序)。每次返回用户自定义长度数量的单词。
            当用户组成新词的时候,加入用户词典;当用户选择旧词的时候,词频尝试+1除非算术溢出。词频采用uint来保存。
            缓冲持久化等下次设计。
    3. 组词器 咋办?

2020年8月29日

嗯,让KeyEventSink承载输入管理器功能。

KeyEventSink:
        输入状态分为英文输入模式、藏文输入模式。当处于英文输入模式的时候,不捕获任何字符。按下shift切换。
        藏文输入模式又分为正常模式、组词模式:
        当处于正常模式下,按下藏文的拉丁转写字母,则进入组词模式;如果按下其他按钮,则输出对应的藏文字符。
        当处于组词模式下,按下拉丁按键,填入拉丁字母输入器。
        当按下拉丁按钮以后,送入正确的拉丁字母串送入用户词典查询。
        捕获所有的标点符号按键,f为音节点,[为候选词上翻页,]为候选词下分页。方向按键为左选择候选词,方向按键为右选择词,默认选择第一个。
        按下空格选择当前词或者按下数字选择词,并从拉丁输入器删除词长度的拉丁字母。每次送入词自动压入栈,如果按下删除键,则回退之前组词。如果拉丁输入器里面没有拉丁字母,则代表组词结束。把词压入用户字典。如果拉丁输入器只剩下错误字符,如果再次按下回车,则把拉丁字母直接送出到宿主。
        按下回车或者shift把拉丁字母直接送出到宿主。按下shitf的时候并进入英文输入模式。

你可能感兴趣的:(经验)