精华内容
下载资源
问答
  • BasicTextService.zip CandidateList.zip Composition.zip CompositionStringUnderline.zip IconInLanguageBar.zip Keyboard.zip PropertyMonitor.zip PropertyTextService.zip TextInsertion.zip ...
  • 输入法开发基础

    2021-07-18 17:06:31
    也正是由于垄断,导致现有的输入法开发项目和开发资料比较少。在这里将自己最近收集的一些内容整理出来,供想做输入法开发的开发人员参考。 输入法开发最为重要的就是开发框架,它是输入法与系统中有输入焦点的应用...

    原文链接

    输入法作为使用频率最高的软件之一,现有市场已经几乎被搜狗输入法垄断。也正是由于垄断,导致现有的输入法开发项目和开发资料比较少。在这里将自己最近收集的一些内容整理出来,供想做输入法开发的开发人员参考。

    输入法开发最为重要的就是开发框架,它是输入法与系统中有输入焦点的应用之间连接的桥梁,将用户输入的文字传输到对应的应用中。

    不同系统下输入法开发使用的框架不同,windows系统下使用的框架有:

    IMM-IME和TSF,Linux系统下使用的框架有fcitx和ibus,不同的框架应对的使用环境和使用场景不同。后面文章我会详细介绍。

    不考虑使用频率较低的外文和少数民族文字,输入法输入针对的语言主要是英语和中文。而英文的输入模式较为单一,这里主要介绍的是中文的输入。

    中文输入依据输入源可以分为:按键输入、语音输入和手写输入,语音输入和手写输入是最近几年随着AI技术发展而逐渐发展起来的输入方式。

    语音输入和手写输入与AI算法关系比较紧密,这里也不做详细介绍。这里介绍一下常规的按键输入,按键输入模式按照输入原理不同可以分为字形输入和拼音输入,拼音输入又根据拆分模式不同分为全拼输入和双拼输入。

    全拼输入就是按照正常的拼音输入然后获取候选词的方式,而双拼输入就是将每个字的音节拆分为声母和韵母,然后将声母和韵母与按键组合映射起来。这样就可以通过输入声母和韵母来输入对应的字了。比如风(feng)可以拆分成声母f和韵母eng,如果键盘上按键A映射f 按键B映射eng,通过AB按键组合输入就可以获得读音为feng的候选。

    字形输入细化之后可以分为五笔输入、拆分输入、笔画输入,五笔输入可以用来输入字或者词而拆分输入和笔画输入主要用来输入比较生僻的字。由于五笔模式大家已经非常熟悉,这里只详细介绍一下拆分输入和笔画输入。在搜狗输入中笔画输入和拆分输入统称为u模式,通过按键u进行启动。

    笔画输入模式中:

    h键代表着笔画中的横

    s键代表着笔画中的竖

    p键代表着笔画中的撇

    n键代表着笔画中的捺

    z键代表着笔画中的折

    比如要想输入木字按笔画可以拆分为横竖撇捺,对应按键hspn然后得到对应的候选结果。

     拆分输入是将不常见的字或者读音比较生僻的字拆分成它的组成部分,然后通过它组成部分的读音获取这个字。比如想输入焱(yan),可以通过输入huohuohuo获得对应的候选。

    为了方便大家的理解和记忆,对各种输入模式进行了整理,列表如下图所示:

    其实输入法使用频率最高的是在全拼输入模式下的词汇和语句的输入,下面对这方面的内容进行详细介绍一下。拼音模式下候选词,依据来源可以分为如下几种。

    自定义短语(与用户定义相关)

    词库短语(与词库相关)

    智能组词短语(与组词模型相关)

    词库联想短语(与词语联想模型相关)

    为了提升全拼输入下的用户输入体验,很多输入法还添加了很多辅助功能,比如:模糊音功能、拼音纠错功能。

    模糊音就是实现固定音节的模糊匹配,下面以搜狗的模糊音进行说明

    我开启了z=zh的模糊音,这样在输入拼音z的时候会自动模糊匹配zh的候选

     而智能纠错,就是将常见的错误拼音纠正成正确的拼音,比如我开启了gn ==>ng的模糊音那么我输入hogn的时候会自动纠正为hong

     

     

     

    依据使用体验来说呢,这两个功能,智能纠错建议全部开启,模糊音建议全部关闭应为会影响候选的精确性。

    依据上面的介绍可以简单介绍一下输入法获取候选的流程:

    1.先根据系统配置获取输入原理是拼音输入还是五笔输入,如果是拼音输入还要确定是全拼输入还是双拼输入。

    2.根据首字母确定输入子模式(是不是笔画输入或者拆分输入)

    3.对输入的字符串进行音节解析,音节包括声母、韵母、以及音调,解析音节的时候要确定是否使用了模糊音和语音纠错。

    4.根据输入的字符串和音节去检索候选词,候选词包括:

    自定义短语、完整的词(从词库中去检索)、通过智能组词组出来的词、单个的字

    简要的流程如下图所示:

    在这个过程中需要的资源包括:

    1.字库

    资源(拆分字库,五笔字库,拼音字库,笔画字库)

    2.词库资源(系统词库,专业词库,云词库,热词词库,英文词库)

    3.自定义短语(系统自定义短语,用户自定义短语)

    4.特殊符号资源

    用户资源中数组结构最复杂的就是词库资源,这里最常见的词库数据结构进行介绍一下,词库其实就是一个二进制文件,具体的内容主要为音节和对应候选词的映射关系,内容主要包括:文件头、数据页两部分。

    文件头中包含了词库的描述信息包括:

    词库的名称

    词库的作者

    词库的词条数

    词条的创建时期

    词库的版本号

    对应词库的索引表

    词库的页数

    其他的额外的描述字段。

    数据页中主要存储了音节和对应的候选词,大家都知道词库的词条数量非常多。如何对候选词进行分类,才能让检索速度更快呢。这里提供一种方案。

    由于词库的词条数据量比较大,需要依据音节对词库进行分页处理,每页中包括一部分词条。每个词条至少包含两个音节(两个字),依据前两个字的声母对词条进行分类,前两个字的声母相同的词条组成一页。而当前页中又存有下一页的编号,这样每种拼音组合的候选词就形成了一个链表,可以无限扩容。同时为了提高检索速度,每个词汇页的长度是固定的。

    每一个候选页的内容包括:

    1.当前页号

    2.下一页的页号

    3.本页中词汇长度标识 (包含哪些长度的词组)

    4.已使用的数据长度

    5.具体内容数据

    具体内容数据中包含了每个词条信息:

    1.词的有效性

    2.词的长度

    3.音节长度

    4.词频

    5.词的音节数组

    6.词中每个字的Unicode值数组。

    在词库中检索词的流程如下图所示:

    1.先解析出输入的音节数组的前两个音节的声母

    2.根据声母组合以及词库头中音节映射表找到对应音节组合的第一页页码

    3.判断第一页中有没有满足对应音节长度的候选词,有的话进行查找,并加入候选词列表。没有的话查找下一页,依次循环直至查找到最后一页。

    为了方便大家理解词库的数据结构下面画了一张简单的数据结构图

    展开全文
  • 输入法开发日记

    千次阅读 热门讨论 2020-08-04 15:41:21
    2020年7月26日 C++11(及现代C++风格)和快速迭代式开发 – 刘未鹏 | Mind Hacks 《C++ Primer Plus》(第6版) 2020年7月27日 IME输入法编程心得 - FreedomShe - 博客园 ...“/ZI”和“/Gy-”命令行选项不兼容 ...

    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)
      image-20200727151936248

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

    解决方法:

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

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

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

    4.将 /SAFESEH:NO 键入“附加选项”框中,然后点击应用。
    image-20200727151936248

    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++可以直接单步进入代码调试。

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

    这里留个效果图。

    image-20200804153901986

    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月26日

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

    2020年9月5日

    这边对Key的int数值使用System.Windows.Forms.Keys的复制,避免引入过度无用类。

    2020年9月18日

    关于VS项目循环引用问题

          写完才发现Core和Gui项目存在循环引用。现在改为Core引用Gui,然后生成的DLL,由Gui引用。以解决循环引用问题。
           后期肯定要对这俩个强耦合的项目,分离开来。现在先主要以实现功能为目的。

    2020年9月21日

    获取屏幕位置可以由GetCaretPos这个函数得到,该函数定于为

    BOOL GetCaretPos(
      LPPOINT lpPoint
    );
    

    参考:
    MSDN:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcaretpos

    C# GetCaretPos() works improperly? - CodeProject
    https://www.codeproject.com/Questions/559082/GetCaretPos-plusworksplusimproperly-3f

    Point需要使用TSF.TypeLib中的POINT,需要与C++的结构体对齐。

    2020年9月22日

    Core和Gui项目的循环引用可以采用消息队列来解耦。参考进程间使用缓冲通讯。

    2020年9月24日

    关于Core和Gui解耦问题:

    Core --> Gui
    Core依赖于Gui,但是Gui不依赖Core。
    Gui发出事件,Core注册即可。
    Gui事件:

    • 选择候选词 CandidateSelectEvent
    • 翻页 PageChangeEvent
    • 模式改变 InputModeChangeEvent

    问题:在开启候选词输入界面以后,原有的窗口失去焦点,造成无法输入问题。参考:https://zhidao.baidu.com/question/688007159565399804.html

    2020年9月27日

    关于移植到其他平台上输入法不可用问题:

    我之前以为是不兼容Win7造成了,于是在虚拟机里面安装了Win8.1和Win10发现故障照样。之后加入错误日记才发现,是路径问题。VS调试的时候默认把路径指向Debug目录,于是可以加载到字典文件。默认指向ApplicationData。这里打算使用注册表来保存程序目录。

    此外发现了一个很有趣的现象:当当前CMD为管理员模式的时候,启动Install.exe程序就是输出到当前命令行,如果不是管理员模式,则会新开一个命令行窗口输出。

    注册表存放位置为计算机\HKEY_LOCAL_MACHINE\SOFTWARE\TibetInput
    包含InstallLocation(安装位置),Version(版本)

    发现Debug的可以写入注册表,Release写入以后没反应。发现Release输出为x86的程序。

    32位程序在64位系统读注册表问题_Keep Moving~-CSDN博客 https://blog.csdn.net/c_base_jin/article/details/80947204?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf

    .net - 如何使用.NET判断我是在x64还是x86上? - IT工具网
    https://www.coder.work/article/6903606

    2020年10月20日

    context.GetSelection一直报错System.StackOverflowException 原因不明

    TF_DEFAULT_SELECTION在此电脑上为4294967295,不知道其他地方时候一样。

    猜测是C#的数组没对齐,和C++数组不一样。

    原来是TSF.TypeLib中的错误

    接口ITfContext中函数需要改为HRESULT GetSelection([In] TfEditCookie ec, [In] uint ulIndex, [In] uint ulCount, [Out] TF_SELECTION[] pSelection, [NullAllowed] out uint pcFetched);函数需要改为HRESULT GetSelection([In] TfEditCookie ec, [In] uint ulIndex, [In] uint ulCount, [Out,MarshalAs(UnmanagedType.LPArray)] TF_SELECTION[] pSelection, [NullAllowed] out uint pcFetched);

    考虑到是7年前的项目了,我打算Fork一下,对其BUG修复。

    2020年10月21日

    逗比的输入法实现 – Yang Yuan – 一个正常的攻城狮
    https://yangyuan.github.io/post/2015-01-08-zh-meow-ime/

    2020年10月30日

    How Do I Rime with the Code | RIME | 中州韻輸入法引擎 https://rime.im/code/

    rime/weasel: 【小狼毫】Rime for Windows
    https://github.com/rime/weasel

    关于输入文字后,光标不移动问题解决:

    SetText后,使用range.Collapse(ec, TfAnchor.TF_ANCHOR_END);闭合range。之后创建一个ITfselection,并且给当前ITfcontext设置ITfselection即可。

    关键代码如下:

    _selections = new TF_SELECTION[1];
                var res = _context.GetSelection(ec, 4294967295, 1, _selections, out var pcFetched);
    if (pcFetched == 1)
    {
         var range = _selections[0].range;
        res = range.SetText(ec, 0, _words, _words.Length);
        range.Collapse(ec, TfAnchor.TF_ANCHOR_END);
        var selection = new TF_SELECTION
        {
            range = range,
            style = new TF_SELECTIONSTYLE
            {
                ase = TfActiveSelEnd.TF_AE_END,
                fInterimChar = false
            }
        };
        _context.SetSelection(ec, 1, selection);
    }
    

    2020年11月2日

    TF_DEFAULT_SELECTIONmsctf.h中定义,为TS_DEFAULT_SELECTION的别名,TS_DEFAULT_SELECTIONTextStor.h中定义,为( ( ULONG )-1 )。在minwindef.h中,ULONGtypedef unsigned long ULONG

    修改库的函数GetSelectionHRESULT GetSelection([In] TfEditCookie ec, [In] TF_DEFAULT ulIndex, [In] ulong ulCount, [Out, MarshalAs(UnmanagedType.LPArray)] TF_SELECTION[] pSelection, [NullAllowed] out ulong pcFetched);

    修改库的函数GetSelectionHRESULT GetSelection([In] TfEditCookie ec, [In] TF_DEFAULT ulIndex, [In] uint ulCount, [Out, MarshalAs(UnmanagedType.LPArray)] TF_SELECTION[] pSelection, [NullAllowed] out uint pcFetched);

    注意:X86不支持ulong,但是在x64使用uint也是可以的。因此这边只能定义为uint。

    在虚拟机上调试输入法

    在自己电脑(win10 2004 专业版)上可以运行,但是到了虚拟机(win7 x86 sp1专业版)上不能运行。

    参考《VS远程调试虚拟机中的程序》,在虚拟机上调试输入法步骤如下:

    1. 虚拟机设置为桥接模式,复制物理机网络状态。
      image-20201102110812684
    2. 然后选择连接。(这里主要是为了避免win10在虚拟机中自动更新的问题。)
      image-20201102111035107
    3. 查看网络共享 => 本地连接 =>状态 => 详细信息,获取虚拟机的IP地址。
    4. 设置VS项目属性 => 调试页:
      image-20201102112241268
    5. 将VS所在目录下的远程调试工具复制到虚拟机, 我的是D:\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\Remote Debugger
      目录下有3个文件夹,复制对应操作系统位数的文件夹即可。比如我这里复制x86这个文件夹。
    6. 运行虚拟机中 Remote Debugger目录下的msvsmon.exe 然后点击选项 => 无身份验证,运行任何用户进行调试。
      最长空闲时间可以改大点: 100000000000000000
    7. 右键项目 => 调试 => 启动新实例调试。
      之后就可以看见,在虚拟机里面启动了一个记事本程序。

    * 目前在IE下有问题。
    原因为失去焦点后重返焦点时候,输入框不会被选中问题。

    2020年11月3日

    阅读小狼毫输入法发现

    ITfKeyEventSink::OnTestKeyDown

    Some apps sends strange OnTestKeyDown/OnKeyDown combinations:
    Some sends OnKeyDown() only. (QQ2012)
    Some sends multiple OnTestKeyDown() for a single key event. (MS WORD 2010 x64)
    We assume every key event will eventually cause a OnKeyDown() call.
    We use _fTestKeyDownPending to omit multiple OnTestKeyDown() calls, and for OnKeyDown() to check if the key has already been sent to the server.

    一些应用在发送OnTestKeyDown/OnKeyDown存在古怪的组合。一些应用只会发送OnKeyDown()(QQ2012);一些应用对于一个单独的按键事件,发送多次的OnTestKeyDown()(MS WORD 2010 x64)。我们假定所有的按键事件都会调用OnKeyDown() 函数。我们使用_fTestKeyDownPending标识来忽略多次调用OnTestKeyDown(),这可以确保OnKeyDown()的按键是否已经被发送到了服务端。

    IE焦点的问题:

    给WPF的Windows窗口设置GetActiveWindow属性为false。属性说明为:获取或者设置一个值,只是首次显示时候,将激活窗口。
    然而,新的问题又产生了,在网页输入的时候,IE的候选框位置不在文本输入光标下面的。此外还有窗口移动问题,这里需要实时更新候选框的位置。

    2020年11月6日

    之前还有遗留的BUG:

    1. 点击任意UI,原有的文本输入框失去焦点问题。
    2. 点击候选词UI,不会选中候选词问题。
    1. 第一个问题的解决:

    .NET/C# 使窗口永不激活(No Activate 永不获得焦点) - 云+社区 - 腾讯云
    https://cloud.tencent.com/developer/article/1341125

    pinvoke.net: the interop wiki!
    https://www.pinvoke.net/

    但是问题还是没有解决。目测输入法的焦点属于进程内交换。思考。

    2020年11月8日

    智能蒙古文输入法的设计与实现 - 中国知网 https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CMFD&dbname=CMFD201902&filename=1019884573.nh&v=IpjW3sgiQW3uYl5Ozq3rR6Q3IEqyLhHzE5e0KW7T57TvN4mSr%25mmd2FoM7rwMMqIy7h1U

    定制化安卓输入法设计及实现 - 中国知网 https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&dbname=CJFDLAST2020&filename=WDZC202006034&v=JA2CxKc59OkUa%25mmd2BppFhZXzA0tXYslouxg7U2W3Au8stO8iDgYdRIHdVhNmwWBaaP7

    2020年11月17日

    设计字典的时候,必须注意大端小段问题,详细见:https://blog.csdn.net/z736248591/article/details/109458524#_96

    2020年11月20日

    ITfUIElementMgr::BeginUIElement:

    The ITfUIElementMgr::BeginUIElement method is called by a text service before showing UI. The value returned determines whether the UI for the text service should be shown or not.

    文字服务在显示UI之前,需要先调用ITfUIElementMgr::BeginUIElement。根据返回的数值来判断UI界面时候需要显示。

    2020年11月28日

    ComRegisterFunctionAttribute 使你能够添加任意注册代码以满足 COM 客户端的要求。 例如,你可以使用命名空间中的注册函数更新注册表 Microsoft.Win32 。 如果提供了注册方法,还应将应用 System.Runtime.InteropServices.ComUnregisterFunctionAttribute 于注销方法,这会反转注册方法中完成的操作。

    .NET Framework: 公共语言运行时使用此属性调用方法,方法是将其包含的程序集注册 (直接或间接) 使用 Regasm.exe (程序集注册) 工具) 或通过 RegistrationServices.RegisterAssembly 方法。

    .Net Core: 当公共语言运行时通过 RegSvr32.exe 工具注册了包含程序集的 COM 主机时,公共语言运行时将调用具有此特性的方法。

    此属性只能应用于具有以下特征的方法:

    • 范围:任何 (public、private 等) 。
    • 键入:static
    • 参数:接受单个 Type 参数或 String 参数类型。
    • 返回类型: void

    2020年11月29日

    CA1416警告:平台兼容性问题

    来源:https://docs.microsoft.com/zh-cn/dotnet/core/compatibility/code-analysis/5.0/ca1416-platform-compatibility-analyzer

    .NET code analyzer rule CA1416 is enabled, by default, starting in .NET 5.0. It produces a build warning for calls to platform-specific APIs from call sites that don’t verify the operating system.

    在.NET5上,开始默认启动CA1416警告。

    你可以在IF语句中,使用 任意一个Is<Platform> 方法来判断:

    public void PlayCMajor()
    {
        if (OperatingSystem.IsWindows())
        {
            Console.Beep(261, 1000);
        }
    }
    

    或者你不喜欢在运行的时候使用一个IF语句来判断,你可以调用Debug.Assert(Boolean) 来代替:

    public void PlayCMajor()
    {
        Debug.Assert(OperatingSystem.IsWindows());
        Console.Beep(261, 1000);
    }
    

    如果你是一个库的作者,你可以给你的API添加特殊平台标记。在这种情况下,确认平台的任务就交给了调用者。你可以将其标记在一个方法或者一个整个程序集上。

    [SupportedOSPlatform("windows")]
    public void PlayCMajor()
    {
        Console.Beep(261, 1000);
    }
    

    2020年12月2日

    ITfInputProcessorProfileMgr interface (msctf.h)

    The ITfInputProcessorProfileMgr interface is implemented by the TSF manager and used by an application or text service to manipulate the language profile of one or more text services.

    不同于 ITfInputProcessorProfiles, ITfInputProcessorProfileMgr可以同时管理按键布局和文字服务程序集。在 Windows Vista下, it is recommended to use this interface instead of using the following methods:

    • ITfInputProcessorProfiles::Register
    • ITfInputProcessorProfiles::Unregister
    • ITfInputProcessorProfiles::AddLanguageProfile
    • ITfInputProcessorProfiles::RemoveLanguageProfile
    • ITfInputProcessorProfiles::EnumInputProcessorInfo
    • ITfInputProcessorProfiles::ActivateLanguageProfile
    • ITfInputProcessorProfiles::GetActiveLanguageProfile
    • ITfInputProcessorProfiles::EnumLanguageProfiles

    ITfInputProcessorProfileMgr::RegisterProfile method (msctf.h)

    The ITfInputProcessorProfileMgr::RegisterProfile method registers the text service and the profile.

    Syntax

    HRESULT RegisterProfile(
      REFCLSID    rclsid,
      LANGID      langid,
      REFGUID     guidProfile,
      const WCHAR *pchDesc,
      ULONG       cchDesc,
      const WCHAR *pchIconFile,
      ULONG       cchFile,
      ULONG       uIconIndex,
      HKL         hklsubstitute,
      DWORD       dwPreferredLayout,
      BOOL        bEnabledByDefault,
      DWORD       dwFlags
    );
    

    Parameters

    rclsid
    

    [in] CLSID of the text service.

    langid
    

    [in] The language id of the profile.

    guidProfile
    

    [in] The GUID to identify the profile.

    pchDesc
    

    [in, size_is(cchDesc)] The description of the profile.

    cchDesc
    

    [in] The length of pchDesc.

    pchIconFile
    

    [in, size_is(cchFile] The full path of the icon file.

    cchFile
    

    [in] The length of pchIconFile.

    uIconIndex
    

    [in] The icon index of the icon file for this profile.

    hklsubstitute
    

    [in] The substitute hkl of this profile.

    dwPreferredLayout
    

    [in] Unused. this must be 0.

    bEnabledByDefault
    

    [in] True if this profile is enabled by default.

    dwFlags
    

    [in] The combination of the following bits:

    ValueMeaning
    TF_RP_HIDDENINSETTINGUIThis profile will not appear in the setting UI.
    TF_RP_LOCALPROCESSThis profile is available only on the local process.
    TF_RP_LOCALTHREADThis profile is available only on the local thread.

    其中有个HKL代替不太懂。上网找了一下:参考:https://www.geek-share.com/detail/2680786863.html

    HKL:键盘布局,最初的含义就是单纯的键盘布局,能够将键盘的扫描码转换成设备无关的虚键码。现在HKL的含义更广泛,表示本地化标识符。

    HKL名字:键盘布局编号,设备码和语言代码组成。前四位是设备码,后四位是语言码。注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts中列出了所有键盘布局。项名就是HKL名称。

    “00000804” 表示 中文(简体) - 默认键盘
    “E0220804” 表示 中文(简体) - 搜狗输入法
    “E0230804” 表示 中文(简体) – 必应Bing输入法

    思考:是不是能挂载在藏语下使用中文键盘?

    2020年12月3日

    https://docs.microsoft.com/en-us/globalization/windows-keyboard-layouts

    Windows Keyboard Layouts

    Choose a keyboard below to view its layouts. To see different keyboard states, move the mouse over state keys such as Shift, Caps or AltGr. You can also lock or unlock those keys by clicking them.

    If you use a pop-up blocker, please update your allowable list to include this Web site. Use the browser magnification feature to increase the size of the keyboards.

    http://systemmanager.ru/win2k_regestry.en/58553.htm

    DosKeybCode

    HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout\DosKeybCodes

    Description

    Represents a keyboard layout.

    These entries are named by 8-digit hexadecimal Windows 2000 keyboard layout codes. The first four digits of the codes indicate whether the [keyboard layout](javascript:startpopups(‘keyboardlayout’)) or [Input Method Editor](javascript:startpopups(‘inputmethodeditor’)) is the default layout for the language (indicated by all zeros) or a variation of the default (other than zeros). The last four digits are the standard [locale](javascript:startpopups(‘locale’)) ID. For example, the 0001040A entry represents variation 0x0001 of language 0x040A (Spanish.)

    All entries have the following format:

    Layout code number REG_SZ Two-character MS-DOS keyboard layout name

    For example,

    0001040A REG_SZ sp

    This entry associates Windows 2000 keyboard layout 0x0001040A with MS-DOS keyboard layout sp.

    Note ImageNote

    The entry is a variable representing the entries under the HKLM\SYSTEM\CurrentControlSet\Control\DosKeybCodes subkey. It does not actually appear in the registry. This variable subkey displays the entries of the DosKeybCodes subkey.

    0x00000409对应US键盘

    ITfInputProcessorProfiles::SubstituteKeyboardLayout method (msctf.h)

    Contains an HKL value that specifies the input locale identifier for the substitute keyboard. Obtain this value by calling LoadKeyboardLayout.

    LoadKeyboardLayout

    函数功能:该函数给系统中装入一种新的键盘布局,可以同时装入几种不同的键盘布局,任一时刻仅有一个进程是活动的,装入多个键盘布局使得在多种布局间快速切换。
      函数原型:HKL LoadKeyboardLayout(LPCTSTR pwszKLID,UINT Flags);
      参数:
      pwszKLID:缓冲区中的存放装入的键盘布局名称,名称是由语言标识符(低位字)和设备标识符(高位字)组成的十六进制值串,例如 U.S.英语对应的语言标识符为DX0409,则基本的U.S.英语键盘布局命名为“0000409”。U.S.英语键盘布局的变种(例如Dvorak布局)命名为“00010409”,“00020409”等。
      Flags:指定如何装入键盘布局,该参数可以是如下的值。
      KLF_ACTIVATE:若指定布局尚未装入,该函数为当前线程装入并激活它。
      KLF_NOTELLSHELL:当装入新的键盘布局时,禁止一个ShellProe过程接收一个HSHELL_LANGUAGE代码。
      当应用程序依次装入多个键盘布局时,对除最后一个键盘布局外的所有键盘布局使用该值,将会延迟Shell的处理直到所有的键盘布局均己被装入。
      KLF_RECOROER:将指定键盘布局移动到布局表的头部,使得对于当前线程,该布局的活动的。若不提供DLF_ACTIVATE值,则该值记录键盘布局表。
      KLF_REPLACE_LANG:Windows NT 4.0或Windows 95以上支持,若新布局与当前布局有同样的语言标识符,那么新布局替代当前布局作为那种语言的键盘布局,若未提供该值,而键盘布局又有同样的标识符,则当前布局不被替换,函数返回NULL值。
      KLF_SUBSTITUTE_OK:用用户喜欢的键盘布局来替换给定布局,系统初始时设置该标志,并且建议始终设置该标志,仅当在注册HKEY_CURRENT_USER/Keyboard Layout/Substitate下定义了一个替代布局时,才发生替换。例如,在名为00000409的部分中有一个多于00010409的值,则设置该标志装入U.S.英语键盘布局会导致Dvorak US.英语键盘布局的装入。系统引导时使用该参数,建议在所有应用程序装入键盘布局时使用该值,以确保用户喜欢的键盘布局被选取。
      KLF_SETFORPROCESS:Windows NT 5.0该位仅法与KLF_ACTIVATE一起使用时才有效,为整个进程激活指定键盘布局,且发送WM_INPUTLANGCHANGE消息以当前进程的所有线程。典型的LoadKeyboardLayWut仅为当前线程激活一个键盘布局。
      KLF_UNLOADPREVIOS:WindowsNT5.0,Windows95,Windows98都不支持,仅当与KLF_ACTIVATE一起使用时才有效,仅当装入且激活指定键盘布局成功,先前的布局才能被卸载,建议使用unLoadKeyboardLayout函数。
      返回值:若函数调用成功,返回与要求的名字匹配的键盘布局句柄。若没有匹配的布局,则返回NULL。
      备注:应用程序可以通过仅定义语言标识符的串来装入该语言的IME向缺省键盘布局。若应用程序想装入IME的指定键盘布局,就必须读注册信息以确定传递给LoadKeyboardLayout返回的键盘布局句柄来激活。
      Windows 95和Windows 98:若装载与原先键盘布局使用同种语言的布局,且KLF_REPLACELANG标志未被设置,则函数调用失败,仅有一个键盘布局可与给定语言相关联。(对于装载与同一语言相关的多IME也是可接受的)。
      速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:不支持;头文件:winuser.h;库文件:user32.lib;Unicode:在Windows NT上实现为Unicode和ANSI两种版本。

    2020年12月4日

    net5 failed to load the dll from [C:\Users\ZMK\Desktop\publish\coreclr.dll] HRESULT 0x80070057

    解决方案:https://developercommunity.visualstudio.com/content/problem/805039/net-core-30-failed-to-load-dll.html

    需要下载KB2533623 补丁。下载地址:http://www.3h3.com/soft/119473.html

    Windows 7 / Vista / 8.1 / Server 2008 R2 / Server 2012 R2

    如果您在以下系统安装.NET SDK或者运行环境的话,需要添加依赖::

    • Windows 7 SP1 ESU
    • Windows Vista SP 2
    • Windows 8.1
    • Windows Server 2008 R2
    • Windows Server 2012 R2

    需要安装以下依赖:

    2021年1月21日

    查询只有7个的问题

    原语句为var q = _list.AsParallel().WithCancellation(tokenSource.Token).Where(item => item.IsBeginWith(syllables)).OrderByDescending(item => item.Syllables.Length).ThenByDescending(item => item.Frequency).Take(num).Skip(skip);
    linq的Take和Skip存在先后顺序。如果这样子查询,则第二页的数目就不正确。
    Skip必须要在Take前面。
    修改完以后为var q = _list.AsParallel().WithCancellation(tokenSource.Token).Where(item => item.IsBeginWith(syllables)).OrderByDescending(item => item.Syllables.Length).ThenByDescending(item => item.Frequency).Skip(skip).Take(num);
    翻页后就正确了。

    候选词采用带权重的函数

    p(x)为候选词x的优先度。候选词列表按照从主序为匹配长度从高到低,次序为优先度从高到低排序。
    p ( x ) = k ( x ) ∗ f ( x ) p(x) = k(x) * f(x) p(x)=k(x)f(x)
    其中: f ( x ) f(x) f(x)代表使用频率, k ( x ) = { 17 i n p u t = x 2 x 为 用 户 自 己 造 词 1 其 他 情 况 k(x)=\begin{cases} 17 & input=x\\2 & x为用户自己造词\\ 1 & 其他情况\end{cases} k(x)=1721input=xx

    2021年1月28日

    句柄查看工具

    • LookHandles是一款非常实用的句柄查看软件,可以帮助用户对任何程序句柄进行捕捉,还可以清晰地显示窗口信息,根据相应的逻辑获取句柄信息。

    • Handle(句柄小助手)是一款功能强大的句柄小助手,常常被程序员用于获取打开窗口的信息毛病进行整理加工。

    使用WND给WPF设置父窗口:

    这个试了一下,也是没用的。最后只能放弃C#的WPF,转用C++的MFC。

    .NET/C# 使窗口永不激活(No Activate 永不获得焦点) - 云+社区 - 腾讯云 https://cloud.tencent.com/developer/article/1341125

    这个发现,必须要保证handle已经创建。

    var interop = new WindowInteropHelper(this);
    interop.EnsureHandle();
    var handle = interop.Handle;
    

    2021年2月3日

    查看DLL是X86还是X64

    使用VS开发环境

    dumpbin.exe /headers D:\CraneSimulation\x64\Debug\UaClientApi.dll
    

    Windows下SysWow64和System32

    参考:https://blog.csdn.net/oncealong/article/details/50477997

    Windows作为一个操作系统,自然希望用户在运行64位操作系统时,也能像以前一样,运行各种32位应用程序。Wow64指的是64位Windows上的32位Windows,SysWow64里放的是32位的系统文件。

    输入法有时候加载不出来的问题解决(半年了终于找到问题所在)

    默认运行在X86上,X64的程序调用不了。

    注意生成目标改为Any CPU,记住别勾选上首选32位,不然会运行在x86环境下。

    2021年2月12日

    试了一下在新建的线程上创建WPF窗口,提示错误,必须要在STA线程上创建。这里只能启动一个新进程。

    调用线程必须为 STA,因为许多 UI 组件都需要 - 金虹巴巴 - 博客园 https://www.cnblogs.com/furenjian/articles/3224493.html

    SerializationException无法找到程序集

    System.Runtime.Serialization.SerializationException:“无法找到程序集“Global, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”。”
    

    新建一个类UBinder

    public class UBinder : SerializationBinder
        {
            public override Type BindToType(string assemblyName, string typeName)
            {
                // 从E:\TibetGlobal.dll读取
                var path = Path.Combine("E:\\", "TibetGlobal.dll");
                var assembly = Assembly.LoadFrom(globalPath);
                return assembly.GetType(typeName);
                }
            }
        }
    

    使用这个类

    var formatter = new BinaryFormatter
    {
        Binder = new UBinder()
    };
    var obj = formatter.Deserialize(pipeServer);
    

    2021年2月15日

    C# file not found in System32 when running in 32 bit - Stack Overflow
    https://stackoverflow.com/questions/30533924/c-sharp-file-not-found-in-system32-when-running-in-32-bit

    2021年2月16日

    发现在x86和x64环境下注册输入法的环境不一样。要在x86和x64环境下都注册一下。而x86和x64下,C#生成的DLL均为Any CPU,均可以通用。

    注册的内容为

    通过RegAsm.exe /regfile TibetCore.dll查看。

    2021年2月18日

    Inno Setup 检测已安装的.NET Framework 版本

    ;.NET Framework 安装文件
    #define DotNetSetupFile "ndp48-web.exe"
    ; 上述消息放置到脚本的顶部
    
    [Code]
    const CDotNetSetupFile = '{#DotNetSetupFile}';
    var VNeedRestart: boolean;
    function IsDotNetDetected(version: string; service: cardinal): boolean;
    // Indicates whether the specified version and service pack of the .NET Framework is installed.
    //
    // version -- Specify one of these strings for the required .NET Framework version:
    //    'v1.1'          .NET Framework 1.1
    //    'v2.0'          .NET Framework 2.0
    //    'v3.0'          .NET Framework 3.0
    //    'v3.5'          .NET Framework 3.5
    //    'v4\Client'     .NET Framework 4.0 Client Profile
    //    'v4\Full'       .NET Framework 4.0 Full Installation
    //    'v4.5'          .NET Framework 4.5
    //    'v4.5.1'        .NET Framework 4.5.1
    //    'v4.5.2'        .NET Framework 4.5.2
    //    'v4.6'          .NET Framework 4.6
    //    'v4.6.1'        .NET Framework 4.6.1
    //    'v4.6.2'        .NET Framework 4.6.2
    //    'v4.7'          .NET Framework 4.7
    //    'v4.7.1'        .NET Framework 4.7.1
    //    'v4.7.2'        .NET Framework 4.7.2
    //    'v4.8'          .NET Framework 4.8
    //
    // service -- Specify any non-negative integer for the required service pack level:
    //    0               No service packs required
    //    1, 2, etc.      Service pack 1, 2, etc. required
    var
        key, versionKey: string;
        install, release, serviceCount, versionRelease: cardinal;
        success: boolean;
    begin
        versionKey := version;
        versionRelease := 0;
    
        // .NET 1.1 and 2.0 embed release number in version key
        if version = 'v1.1' then begin
            versionKey := 'v1.1.4322';
        end
        else if version = 'v2.0' then begin
            versionKey := 'v2.0.50727';
        end
    
        // .NET 4.5 and newer install as update to .NET 4.0 Full
        else if Pos('v4.', version) = 1 then begin
            versionKey := 'v4\Full';
            case version of
            // from url https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
              'v4.5':   versionRelease := 378389;
              'v4.5.1': versionRelease := 378675; // 378758 on Windows 8 and older
              'v4.5.2': versionRelease := 379893;
              'v4.6':   versionRelease := 393295; // 393297 on Windows 8.1 and older
              'v4.6.1': versionRelease := 394254; // 394271 on Windows 8.1 and older
              'v4.6.2': versionRelease := 394802; // 394806 on Windows 8.1 and older
              'v4.7':   versionRelease := 460798; // 460805 On all other Windows operating systems (including other Windows 10 operating systems)
              'v4.7.1': versionRelease := 461308; // 461310 On all other Windows operating systems (including other Windows 10 operating systems)
              'v4.7.2': versionRelease := 461808; // 461814 On all Windows operating systems other than Windows 10 April 2018 Update and Windows Server, version 1803
              'v4.8'  : versionRelease := 528040; // On Windows 10 May 2019 Update and Windows 10 November 2019 Update: 528040; On Windows 10 May 2020 Update and Windows 10 October 2020 Update: 528372; On all other Windows operating systems (including other Windows 10 operating systems): 528049
            end;
        end;
    
        // installation key group for all .NET versions
        key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + versionKey;
    
        // .NET 3.0 uses value InstallSuccess in subkey Setup
        if Pos('v3.0', version) = 1 then begin
            success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install);
        end else begin
            success := RegQueryDWordValue(HKLM, key, 'Install', install);
        end;
    
        // .NET 4.0 and newer use value Servicing instead of SP
        if Pos('v4', version) = 1 then begin
            success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
        end else begin
            success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
        end;
    
        // .NET 4.5 and newer use additional value Release
        if versionRelease > 0 then begin
            success := success and RegQueryDWordValue(HKLM, key, 'Release', release);
            success := success and (release >= versionRelease);
        end;
    
        result := success and (install = 1) and (serviceCount >= service);
    end;
    
    function InitializeSetup(): Boolean;
    var IEPath, NetV2DownUrl, DotNetPath:string;
    var ResultCode:Integer;
    begin
        VNeedRestart := false;
    
        if not IsDotNetDetected('v4.8', 0) then begin
          
          if MsgBox('系统缺少程序运行组件.Net Framework 4.8,是否立刻下载并安装?', mbConfirmation, MB_YESNO) = idYes then begin
              // 临时解压安装文件
              ExtractTemporaryFile(CDotNetSetupFile);
              DotNetPath := ExpandConstant('{tmp}\'+CDotNetSetupFile);
              // 运行
              if Exec(DotNetPath,'/norestart /passive /showfinalerror','',SW_SHOWNORMAL,ewWaitUntilTerminated,ResultCode) then begin
                  if ResultCode = 0 then begin
                      result := true;
                  end else if (ResultCode = 1641) or (ResultCode = 3010) then begin
                      // 需要重新启动才能完成安装。 此消息指示安装成功。
                      VNeedRestart := true;
                      result := true;
                  end else begin
                      result := false;
                  end
              end else begin
                  MsgBox('运行.Net Framework 4.8安装程序失败!',mbError,MB_OK);
                  result := false;
              end
          end
        end else begin
            result := true;
        end
    end;
    
    function NeedRestart(): Boolean;
    begin
      result := VNeedRestart;
    end;
    

    安装程序可以从微软官方下载:
    https://dotnet.microsoft.com/download/dotnet-framework

    参考:

    确定已安装的 .NET Framework 版本 | Microsoft Docs
    https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed

    Inno Setup 判断.NET是否安装_tcmtang的博客-CSDN博客 https://blog.csdn.net/tcmtang/article/details/49932205

    Inno Setup 检测已安装的.NET Framework 版本 - 知乎
    https://zhuanlan.zhihu.com/p/51658788

    2021年2月20日

    Inno Setup覆盖安装几次后,UninstallRun就会执行几次问题。

    1. 使用[RunOnceId]:

    仅在 [UninstallRun] 段有效。如果已经安装了相同的应用程序,卸载日志文件中的“run”条目将被复制一个副本。通过分配一个字符给 RunOnceId,可以确保在卸载期间特殊的 [UninstallRun] 条目只执行一次。例如,如果卸载日志中有两个或更多“run”条目用“DelService”的 RunOnceId 设置,只执行最后一个用“DelService”的 RunOnceId 设置的条目;其它的将被忽略。注意 RunOnceId 比校是区分大小写的。

    1. 安装前删除旧版本。

    参考:

    installation - Inno Setup: How to automatically uninstall previous installed version? - Stack Overflow https://stackoverflow.com/questions/2000296/inno-setup-how-to-automatically-uninstall-previous-installed-version#

    2021年2月22日

    .NET5 创建Windows Service

    Creating a Windows Service with C#/.NET5 | #ifdef Windows
    https://devblogs.microsoft.com/ifdef-windows/creating-a-windows-service-with-c-net5/

    展开全文
  • MDCC 2016 中国移动开发者大会前夕,iOS 开发峰会演讲嘉宾——搜狗输入法 iOS 版负责人李腾杰接受 CSDN 专访,分享了其与团队在第三方输入法开发与优化方面的经验,以及搜狗输入法 iOS 版开发团队在新技术与一线项目...

    输入法是一种对性能要求极高的产品,不同于普通应用开发,很多在普通应用开发看来不是问题的,在输入法看来却是比较关键。同时,由于 iOS 系统的某些限制,输入法不得不在产品功能和性能方面做出调整,以尽可能地优化用户体验。在MDCC 2016 中国移动开发者大会前夕,iOS 开发峰会演讲嘉宾——搜狗输入法 iOS 版负责人李腾杰接受 CSDN 专访,分享了其与团队在第三方输入法开发与优化方面的经验,以及搜狗输入法 iOS 版开发团队在新技术与一线项目开发相结合的尝试与实践。(大会门票 8 折优惠正在进行时,欲购从速!票务详情链接

    搜狗输入法 iOS 版负责人 李腾杰

    请介绍一下您和目前的工作,以及关注/正在研究的技术。

    李腾杰: 我目前在搜狗公司从事 iOS 平台搜狗输入法的相关研发工作,重点关注输入法关键性能指标(如键盘调起速度、内存、CPU 等)和代码架构的优化。同时,也在研究 Swift 3,在合适的时间点安排项目适配 Swift 3。

    在 iOS 开发新的技术点方面,搜狗输入法 iOS 版开发团队有着怎样的尝试与实践?

    李腾杰: 在 iOS 动态更新方案上,我们跟进了对 JSPatchReact Native 的调研,最后根据输入法的项目实际情况,择选 JSPatch 应用于输入法,完成了输入法热更新的工作。JSPatch 集成较为简单,是一种应用较广泛的热修复解决方案,它可以通过服务器后台下发 JavaScript 脚本,实时修改 Objective-C 方法的实现,达到修复 Bug 和动态运营的目的。

    由于 JSPatch 存在性能方面的限制,实际项目中仅用于做一些轻量级代码的修复,并没有频繁的使用。考虑到安全性,输入法自行部署了服务器后台来分版本管理下发的脚本,针对键盘扩展和其容器 App 两种类型的下发脚本。同时,由于输入法键盘扩展的特殊性,受到键盘允许完全访问控制权限的影响,输入法尝试了通过键盘容器 App 来获取修复脚本,借由相同 Group 的共享目录来影响键盘。在输入法关键性能指标的优化上,我们也跟进了 FBRetainCycleDetector(Facebook开源的一个内存泄漏检测解决方案)、FastImageCache(Path 团队开发的一个开源库,用于提升图片的加载和渲染速度)的调研,并运用于项目实践,优化产出效果较好,确实发现了一些代码实现中的问题,并改进了输入法换肤的稳定性。

    在搜狗输入法 iOS 版研发与更新过程中,遇到过哪些比较棘手的问题,如何解决的?

    李腾杰: 最棘手的问题,往往是和 iOS 系统相关的,这里举一个输入法遇到的字符绘制产生的诡异崩溃。我们在分析输入法收集的崩溃日志时,曾经遇到一种特别诡异的崩溃,从崩溃栈来看是崩溃在候选绘制上,其占比也挺大,直接影响到输入法的稳定性。单纯分析崩溃栈对应的代码调用,并没有任何问题,也确认了并不是内存越界等造成的崩溃,我们尝试了各种自动化评测或人工操作方案,都没能复现该崩溃。经过初步分析,怀疑是和系统绘制某些特定字符异常导致的崩溃,于是就对崩溃日志收集进行了改进,增加了对崩溃异常时当前候选内容的收集,上线版本后通过收集的崩溃日志,发现对应的候选内容在绘制时并没有任何问题。

    鉴于这种情况,我们在原有自动化评测的基础上,单独抽调一台 iMac 机器,通过 Xcode 真机调试的方式来分多个机型和系统进行更细致的评测,最终在其中一台测试机器上发现了类似崩溃。且发生崩溃时,在 Xcode 上看到的当前绘制候选字符是一个表示“哭”的颜文字表情。一般情况下绘制该表情并不会有什么问题,我们在该机型上又持续进行了三次长时间的模拟输入评测,有一次崩溃还是与该表情相关。根据这个情况,我们在后续的上线版本中,从词库中剔除了该表情,根据后台监测到的崩溃情况,这个困扰许久的崩溃问题终于得到解决。最终分析结论是 iOS 系统在某些条件下绘制该复杂的表情可能会产生崩溃,而为何会如此,一直也没弄清楚,虽然这个崩溃确实是修复了。

    中文字体文件大,以 Webfonts 的方式加载困难加载比较困难,搜狗输入法是怎么优化的?

    李腾杰: 由于中文字体比较大,且从 iOS 8 开始被系统一旦加载,并不能立即释放,而是由系统决定在什么时机释放,且不能完全释放。针对这种情况,搜狗输入法的候选词绘制并没有开放让用户自定义,而是根据不同的 iOS 系统,使用其默认的系统字体;输入法在皮肤个性化里,允许皮肤作者自定义键盘区域的文本显示字体,并建议皮肤作者将该皮肤对应的字体文件包含的字符集控制在最小够用,避免字体太大导致皮肤下载流量和内存占用的增加。如果输入法被启用的皮肤没有指定字体,则输入法使用当前系统的默认字体。上述方案是输入法认真权衡用户输入性能优先,并兼顾输入法皮肤功能多样性之后,得到的一个优化方案,也避免了中文字体过大对输入法性能带来的压力。

    在输入法框架方面,搜狗输入法是如何实现不同平台代码复用的?

    李腾杰: 搜狗输入法会将某些不同平台共有的基础模块(如输入法内核)使用C/C++来实现,并用宏分隔开平台相关的某些具体 API 实现,封装成统一的接口来供平台调用。在更新某些模块的功能实现时,对平台调用始终透明,尽量保证接口的一致性。

    搜狗输入法的内核模块,划分了接口层、功能逻辑层和设备层三个层次,接口层对应平台代码调用,接口一般相对较为固定,除非大的功能调整才变化。功能逻辑层封装了具体的内核功能逻辑的实现代码,对各个平台是透明的,主要用于接口层的调用。设备层封装了与平台相关的某些API实现,不同平台会有不同的技术实现,如字符串操作、文件操作等,供功能逻辑层调用,一般很少变化。通过这三个层次的封装,内核实现某个新功能时,一般只需要调整功能逻辑层的实现,然后通过内核自动化测试工具来完成测试,就可以方便地提供给各个平台使用,平台调用也不用做什么接口层的更改。

    搜狗输入法的 Emoji、颜文字一直以来都颇受用户喜爱,使用率非常高,在这方面你们做了哪些工作?

    李腾杰: 在不同的 iOS 系统上,Emoji 表情的显示效果可能会有差异,且随着 iOS 系统的更新,Emoji 表情编码也会有新增或更改,这就要求输入法始终关注每个 iOS 系统的 Emoji 全集,及时更新到输入法中。搜狗输入法通过自动化评测的手段来分析每个 iOS 版本其系统表情键盘的 Emoji 表情全集,看是否有新的变化,并及时跟进更新。同时,Emoji、颜文字等表情字符的绘制又比较消耗资源,输入法尝试了提前将字符绘制成图片打包的方式来解决实时绘制表情字符造成的内存压力;并考虑到相同 Emoji 编码在不同 iOS 系统上的显示效果差异,又调研了在 iOS 9 及以上系统绘制 Emoji 表情不缓存的技术解决方案,将图片和绘制两种方式结合使用,保证了 Emoji 和颜文字表情功能的良好性能。除此之外,输入法提供了表情商城,用户可以在里面很方便地下载到颜文字表情包、图片表情等,大大丰富了用户的输入体验。

    Emoji、颜文字功能内存方面的优化实践,在后续的 MDCC 2016 移动开发者大会上会详细介绍。

    从 2009 年加入搜狗从事输入法的相关研发工作至今,从您的亲身实践来看,iOS 系统对于第三方输入法研发的支持有着怎样的改进与发展?就目前而言,在开发过程中,还有哪些特别想吐槽的限制?

    李腾杰: iOS 系统在 iOS 8 上才开始开放第三方输入法的研发,在这之前,只能通过越狱的方式来进行第三方输入法的研发,Hook 系统输入法相关的 API 来实现输入法的功能。越狱方式开发输入法不容易,每每 iOS 系统更新,第三方输入法都需要及时跟进,调研该 iOS 系统输入法相关 API 是否有变更,并在新的越狱工具出来之后,以最快的速度去跟进适配,保证用户率先用上最稳定的输入法。

    但越狱输入法由于 iOS 系统的限制,性能和稳定性方面难免存在一些避免不了的问题,很难将输入法体验做到完美。且越狱输入法的安装门槛也比较高,阻隔了很大一部分用户的第三方输入法需求。从 iOS 8 开始,iOS 系统对第三方输入法的研发提供了支持,接口也比较稳定,开发者在适配不同 iOS 系统上耗费的精力也少了很多,广大用户也能很便捷地通过 App Store 安装自己想要的输入法,皆大欢喜的场面。

    即便如此,iOS 系统至今仍有的某些限制,仍给第三方输入法造了不少麻烦事儿,主要有以下三个点:

    1. 首先,是系统第三方自定义键盘框架的稳定性不够,诸如升级输入法后旧版本的输入法进程仍存在、未能及时更新导致某些界面显示异常或崩溃;键盘无法调起;键盘需要重新添加等等,都给用户体验造成了较大影响,而第三方输入法又无能为力。
    2. 其次,是iOS系统对第三方键盘的诸多限制,如允许完全访问控制权限的限制,限制了用户需要开启入口隐蔽的权限开关,才能体验到输入法的某些特色功能;而且,由于iOS系统的限制,第三方键盘并没有如系统键盘一样被系统一视同仁,键盘调起体验始终无法像系统键盘那么流畅。
    3. 再者,是iOS系统对第三方键盘的资源使用限制比普通App更为严格,一旦第三方键盘使用的内存被它认为较多或系统内存紧张,就会直接kill键盘进程,切换成其它输入法,直接影响了输入法的稳定性,也对输入法开发的性能优化提出了相比越狱输入法更高的挑战。

    根据您的经验,当前在开发第三方 iOS 输入法方面,开发团队所面临的主要挑战是什么?在此过程中又容易陷入怎样的误区?

    李腾杰: 输入法不同于普通 App 的开发,对性能非常敏感,开发团队面临的主要挑战是兼顾功能效率的同时如何充分保障性能,并让每个开发组员都对性能足够敏感和关注。在实际项目过程中,针对某些涉及敏感性能的技术实现方案,可能会涉及到新技术的使用,需要避免“它性能应该没问题”这种猜测方式,通过评测来评估新技术的性能如何,这看起来有点麻烦,但确实省不得。

    输入法在最初适配不同键盘尺寸的按键布局时,使用了 Autolayout 的解决方案,Autolayout 方法简单、强大易用、可读性强,但是 updateConstraints 调用时机不一样,计算布局的耗时也不一样;尤其在适配较为复杂的界面依赖布局时,耗时会显著增加,性能会比直接setFrame差。下图所示是某技术同行对Autolayout的性能分析(详见:http://pilky.me/36/)。

    输入法最早就踩了 Autolayout 性能的这个坑,缺少对该技术方案的详细分析评测,影响了键盘调起速度,后续针对键盘调起速度的优化过程中,通过 Instruments 的 Time Profiler 才定位到该问题。

    在输入法某些基础关键性能指标(如键盘调起速度、内存等)的优化上,输入法同样踩过一些坑,这些坑在普通App看来可能并不是太大的问题,但在输入法上体现却相对明显,在 MDCC 上我会就此做详细分享。

    对于输入法的使用,用户比较关心信息安全的问题,搜狗输入法对于用户信息的保护有着怎样的经验?

    李腾杰: 首先,输入法本身不收集用户的任何输入信息,用户输入信息在本地进行运算,并给出对应的候选词结果,然后再调用系统 API 直接上屏到输入框之中,中间不做任何缓存。其次,输入法某些功能需要访问到用户隐私信息时,会在产品交互层面,明确说明访问哪些用户信息及其用途,只有用户允许了该访问,才会进行后续的功能逻辑。再者,iOS 系统为所有的第三方输入法都提供了“允许完全访问控制权限”的选项,用户一旦关闭该选项,那输入法便无法进行联网或访问系统某些权限要求比较高的功能模块。另外,输入法某些功能的联网请求,诸如云输入、词库同步功能,会使用加密方式与服务器进行通信,确保整个通讯过程是非明文可靠的,且整个请求不在服务器缓存任何数据。

    您在 MDCC 2016 上将分享《搜狗输入法性能优化实践》,希望此次演讲能够为听众带来哪些方面的启发?

    李腾杰: 这次分享的搜狗输入法在项目过程中某些关键性能指标的优化实践,希望通过实际案例来说明一些性能优化的方法和建议,与同行共同交流。

    对于您而言,您最期待在 MDCC 2016 上看到哪些内容?收获什么?

    李腾杰: 期待在今年的 MDCC 上看到 iOS、Android 相关新技术如何应用于实际项目,与同行交流性能优化方面踩过的坑,学习好的优化经验。

    更多精彩尽在 MDCC 2016,详情请查看大会官网:MDCC 2016 中国移动开发者大会

    展开全文
  • Android输入法开发

    万次阅读 2017-02-06 17:08:48
    输入法编辑器(IME)是一个便于用户输入文本的控件。Android提供了一个可扩展的输入法框架,允许应用程序提供可替代的输入法,比如屏幕上的键盘或者语音输入。在安装 输入法后,用户可以通过系统选项选择想要使用的...

    输入法编辑器(IME)是一个便于用户输入文本的控件。Android提供了一个可扩展的输入法框架,允许应用程序提供可替代的输入法,比如屏幕上的键盘或者语音输入。在安装
    输入法后,用户可以通过系统选项选择想要使用的输入法。

    想要添加一个输入法,你需要创建一个Android应用并包含一个继承自InputMethodService的类。此外,同城创建一个设置页面来承载输入发的各个选项。你可以自行定义一个设置的UI。

    下面讲述以下几个内容:
    · 输入法的生命周期
    · 在应用的清单文件中定义输入法组件
    · 输入法相关接口
    · 设计一个款输入法的UI
    · 发送文本到应用
    · 输入法子类型的使用

    一、输入法的生命周期

    输入法的生命周期如下图所示:

    输入法生命周期

    下面的部分讲述如何根据输入法的生命周期实现UI和输入法功能。

    二、在清单文件中定义输入法组件
    在Android系统中,IME是一个包含特殊IME服务的应用程序。应用的清单文件必须声明输入法服务,请求必须的权限,提供一个intent filter来匹配 action.view.InputMethod,并提供定义了IME特征的元数据(metadata)。此外,可以定义一个设置页面来提供用户修改IME配置的接口,它可以被系统设置所启动。
    下面的代码片段声明了一个IME服务。请求了 BIND_INPUT_METHOD 权限来允许服务连接到系统的IME,建立intent filter和metadata:

    <!-- Declares the input method service -->
        <service android:name="FastInputIME"
            android:label="@string/fast_input_label"
            android:permission="android.permission.BIND_INPUT_METHOD">
            <intent-filter>
                <action android:name="android.view.InputMethod" />
            </intent-filter>
            <meta-data android:name="android.view.im"
    android:resource="@xml/method" />
        </service>

    下面的代码片段声明了IME的设置页面,它拥有 ACTION_MAIN 的intent filter来表示它是IME程序的主入口。

    <!-- Optional: an activity for controlling the IME settings -->
        <activity android:name="FastInputIMESettings"
            android:label="@string/fast_input_settings">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
            </intent-filter>
        </activity>

    也可以从IME的UI提供直接进入设置的入口。

    三、输入法API
    与IME相关的类在 android.inputmethodservice 和 android.view.inputmethod 包中。KeyEvent 类对于处理键盘特征至关重要。
    IME的核心部分是一个服务组件,即一个继承自InputMethodService的类。此外为了实现一般服务的生命周期,这个类提供了IME的UI,处理用户输入和传输文本到指定区域以及当前焦点的回调。InputMethodService类提供了绝大多数管理IME状态和与当前输入区域交互的实现。

    下面几个类也很重要。
    BaseInputConnection
    定义了输入法和应用之间接收输入的交互通道。使用它来读取光标周围的文本,提交文本到输入框以及发送键盘事件给应用。应用应该集成此类。

    KeyboardView
    一个View的扩展,描绘了一个键盘和用户输入事件的响应。键盘的布局是被Keyboard的实例指定,可以定义一个XML文件。

    四、设计输入法UI
    IME有两个主要的视觉元素:即输入视图和备选视图。你只需要实现和你设计的输入法有关的元素。

    1.输入视图
    输入视图是用户使用按键,手写或者手势在表单中输入文本的UI。
    当IME第一次显示,系统会调用 onCreateInputView() 回调。在你实现的这个方法中,你创建你想要的IME窗口的布局并返回给系统。下面片段是一个例子:

    @Override
        public View onCreateInputView() {
            MyKeyboardView inputView =
                (MyKeyboardView) getLayoutInflater().inflate( R.layout.input, null);
    
            inputView.setOnKeyboardActionListener(this);
    inputView.setKeyboard(mLatinKeyboard);
    
            return mInputView;
        }

    这里的MyKeyboardView是一个自定义的实现了 KeyboardView 的实例,如果你构建的是一个传统的QWERTY键盘,请查看 KeyboardView 类。

    2.候选视图
    候选视图是供用户选择可选词和推荐词的视图。在IME的生命周期中,系统在准备好显示备选视图的时候会调用onCreateCandidatesView()。在你实现的这个方法中,返回显示词汇建议的布局,当什么都不显示时,返回null。
    若要查看实现用户建议词汇的例子,请查看SoftKeyboard示例应用。

    3.UI设计依据
    此部分介绍了一些IME的UI设计思想。

    · 应对多元化的屏幕尺寸
    你的IME的UI必须可以适配不同屏幕的尺寸,且必须处理竖屏和横屏两种方向。在非全屏模式下,为应用程序留出足够的空间以显示文本字段和任何相关联的上下文,使得IME不会占用屏幕一半以上的空间。在全屏模式下没有这个问题。

    · 处理不同的输入类型
    Android的输入框允许你选择一个特殊的输入类型,比如自由文本,数字,网址,邮箱地址,收索内容等。当你实现一个新的IME,您需要检测每个字段的输入类型,并为其提供适当的接口。但是,你不必设置IME以检查用户输入的文本对输入类型有效; 这是拥有文本字段的应用程序的责任。

    当输入字段接收焦点并且您的IME启动时,系统调用 onStartInputView(),传递一个 EditorInfo 对象,该对象包含有关文本字段的输入类型和其他属性的详细信息。 在此对象中,inputType 字段包含文本字段的输入类型。
    输入类型字段是一个包含用于各种输入类型设置的位模式的int参数。 要测试它的文本字段的输入类型,用常量TYPE_MASK_CLASS屏蔽它,像这样:
    inputType & InputType.TYPE_MASK_CLASS
    输入类型位模式可以具有几个值中的一个,包括:
    TYPE_CLASS_NUMBER
    用于输入数字的文本字段。
    TYPE_CLASS_DATETIME
    用于输入日期和时间的文本字段。
    TYPE_CLASS_PHONE
    用于输入电话号码的文本字段。
    TYPE_CLASS_TEXT
    用于输入所有支持的字符的文本字段。

    这些常量在 InputType 的参考文档中有更详细的描述。
    inputType字段可以包含指示文本字段类型的其他位,例如:
    TYPE_TEXT_VARIATION_PASSWORD
    用于输入密码的TYPE_CLASS_TEXT 的变体。 输入法将显示标记,而不是实际文本。
    TYPE_TEXT_VARIATION_URI
    用于输入网址和其他统一资源标识符(URI)的TYPE_CLASS_TEXT 的变体。
    TYPE_TEXT_FLAG_AUTO_COMPLETE
    TYPE_CLASS_TEXT 的变体,用于输入应用程序从字典,搜索或其他工具中“自动完成”的文本。
    记住在测试这些变量时,用适当的常数掩蔽输入类型。 可用的掩码常数在输入类型的参考文档中列出。

    注意:在您自己的IME中,确保在将其发送到密码字段时正确处理文本。 在输入视图和候选视图中的用户界面中隐藏密码。 还要记住,您不应该在设备上存储密码。 要了解更多信息,请参阅“为安全性设计”指南。

    五、向应用程序发送文本
    当用户使用IME输入文本时,您可以通过发送单个键事件或在应用程序的文本字段中编辑光标周围的文本来向应用程序发送文本。 在任一情况下,您都使用 InputConnection 的实例来传递文本。 要获取此实例,请调用 InputMethodService.getCurrentInputConnection() 。

    1.编辑光标周围的文本
    当处理文本字段中现有文本的编辑时,BaseInputConnection 中一些更有用的方法是:
    getTextBeforeCursor()
    返回包含当前光标位置之前的请求字符数的 CharSequence 。
    getTextAfterCursor()
    返回包含当前光标位置后的请求字符数的 CharSequence 。
    deleteSurroundingText()
    删除当前光标位置前后的指定数量的字符。
    commitText()
    向文本字段提交 CharSequence 并设置新的光标位置。

    例如,以下代码段显示如何使用文本“Hello!”替换光标左侧的四个字符:

    InputConnection ic = getCurrentInputConnection();
    
        ic.deleteSurroundingText(4, 0);
    
        ic.commitText("Hello", 1);
    
        ic.commitText("!", 1);
    

    2.在提交之前撰写文本
    如果您的IME执行文本预测或需要多个步骤来组成字形或单词,则可以在文本字段中显示进度,直到用户提交单词,然后您可以用完成的文本替换部分组合。 当你传递给 setComposingText()时,你可以通过添加一个“span”来对文本进行特殊处理。
    以下代码段显示了如何在文本字段中显示进度:

      InputConnection ic = getCurrentInputConnection();
    
        ic.setComposingText("Composi", 1);
    ...
    
        ic.setComposingText("Composin", 1);
    
    ...
    
        ic.commitText("Composing ", 1);

    以下屏幕截图显示了用户看到的页面:
    这里写图片描述这里写图片描述这里写图片描述

    3.拦截硬件按键事件
    即使输入法窗口没有明确的焦点,它首先接收硬件键事件,并且可以选择使用它们或将它们转发到应用程序。 例如,您可能想要使用方向键在UI中导航以在组合期间选择候选项。 您可能还想捕获返回键以关闭源自输入法窗口的任何弹出窗口。
    要拦截硬件键,重写onKeyDown()和 onKeyUp()。 请参阅 SoftKeyboard 示例应用程序的示例。
    记住要为你不想处理的键调用super()方法。

    六、创建IME子类型
    子类型允许IME公开IME支持的多种输入模式和语言。 子类型可以表示:
    · 区域设置,如en_US或fr_FR
    · 输入模式,如语音,键盘或手写
    · IME特有的其他输入样式,表单或属性,例如10键或qwerty键盘布局。

    基本上,模式可以是诸如“键盘”,“语音”等的任何文本。 子类型还可以暴露这些的组合。
    子类型信息用于IME切换器对话框,该对话框可从通知栏和IME设置中使用。 该信息还允许框架直接引出IME的特定子类型。 当构建IME时,使用子类型工具,因为它有助于用户识别和在不同的IME语言和模式之间切换。

    您可以使用元素在输入法的XML资源文件之一中定义子类型。 以下代码段定义了一个具有两个子类型的IME:美国英语语言环境的键盘子类型,法国的法语语言环境的另一个键盘子类型

    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
        <subtype android:name="@string/display_name_english_keyboard_ime"
                android:icon="@drawable/subtype_icon_english_keyboard_ime"
                android:imeSubtypeLanguage="en_US"
                android:imeSubtypeMode="keyboard"
                android:imeSubtypeExtraValue="somePrivateOption=true"
        />
        <subtype android:name="@string/display_name_french_keyboard_ime"
                android:icon="@drawable/subtype_icon_french_keyboard_ime"
                android:imeSubtypeLanguage="fr_FR"
                android:imeSubtypeMode="keyboard"
                android:imeSubtypeExtraValue="foobar=30,someInternalOption=false"
        />
        <subtype android:name="@string/display_name_german_keyboard_ime"
                ...
        />
    />
    

    1.从通知栏中选择TIME子类型
    Android系统管理所有IME公开的所有子类型。 IME子类型被视为它们所属的IME的模式。 在通知栏中,用户可以为当前设置的IME选择可用的子类型,如以下屏幕截图所示:
    这里写图片描述

    这里写图片描述

    2.从系统设置选择IME子类型
    用户可以在“系统设置”区域的“语言和输入”设置面板中控制子类型的使用方式。 在 SoftKeyboard 示例应用程序中,文件InputMethodSettingsFragment.java包含一个在IME设置中实现子类型启用程序的实现。 有关如何在IME中支持输入法子类型的更多信息,请参阅Android SDK中的 SoftKeyboard 示例应用程序。

    这里写图片描述

    3.在IME子类型之间切换
    您可以允许用户通过提供切换键(如球形语言图标)作为键盘的一部分,在多个IME子类型之间轻松切换。 这样做大大提高了键盘的可用性,并可以帮助避免用户的失望。 要启用此类切换,请执行以下步骤:
    (1). 在输入法的XML资源文件中声明 supportsSwitchingToNextInputMethod = “true” 。 您的声明应类似于以下代码段:

    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
            android:supportsSwitchingToNextInputMethod="true">

    (2). 调用 shouldOfferSwitchingToNextInputMethod() 方法。
    (3). 如果方法返回true,则显示切换键。
    (4). 当用户点击切换键时,调用 switchToNextInputMethod(),将false传递给第二个参数。 值false表示系统平等对待所有子类型,而不管它们属于什么IME。 指定true要求系统在当前IME中循环遍历子类型。

    注意:在Android 5.0(API级别21)之前,switchToNextInputMethod()不知道 supportsSwitchingToNextInputMethod 属性。 如果用户切换到IME而没有切换键,他可能会卡在该IME中,无法轻松地切换出来。

    七、一般IME注意事项
    以下是您实现IME时需要考虑的其他事项:
    · 为用户提供一种直接从IME的UI设置选项的方法。
    · 因为设备上可以安装多个IME,所以提供了用于用户从输入法UI直接切换到不同的IME的方式。
    · 快速启动IME的UI。根据需要预加载或加载任何大型资源,以便用户在点击文本字段时看到IME。缓存资源和视图,用于后续调用输入法。
    · 相反,您应该在隐藏输入法窗口后立即释放大量内存分配,以便应用程序可以有足够的内存来运行。如果IME处于隐藏状态几秒钟,请考虑使用延迟消息来释放资源。
    · 请确保用户可以为与IME关联的语言或区域设置输入尽可能多的字符。请记住,用户可以在密码或用户名中使用标点符号,因此您的IME必须提供许多不同的字符,以允许用户输入密码并访问设备。

    展开全文
  • 搜狗拼音输入法开发
  • xcb-imdkit xcb-imdkit是xcb中xim协议的实现,与带有Xlib的IMDkit和位于Xlib内... 在客户端进行语言环境检查,对于输入法而言,这实际上是非常有害的。 仅支持X传输。 要构建此项目,您需要:libxcb,xcb-util,xcb-
  • Android之输入法开发简单说明[参照].pdf
  • 输入法开发

    2015-12-09 21:19:14
    创建一个输入法 输入法是一种可以让用户输入文本的控件。安卓提供一个可扩展的输入法框架,这个框架允许程序提供给用户不同的输入方式,比如屏幕键盘或语音输入。安装好各种各样的输入法后,用户可以通过系统设置...
  • PIME:用于利用Python开发Windows的输入法
  • 触摸屏T9拼音输入法开发包..rar
  • Android平台输入法开发解析 解析android inputmethod
  • Android之输入法开发简单说明.pdf
  • Android平台输入法开发解析[参考].pdf
  • ibus输入法开发记录:(一)概览参考资料导航ibus简介ibus自定义输入法开发简介组件和引擎接入组件初始化ibus程序调试 参考资料导航 ibus源代码:https://github.com/phuang/ibus ibus-pinyin源代码:...
  • 转自:http://www.cnblogs.com/weixing/archive/2013/09/04/3300947.html从SDK 1.5版本以后,...而开发输入法最好的参考就是Android自带的Sample-SoftKeyboard,虽然这个例子仅包含英文和数字输入,但是它本身还算完整
  • 安卓平台输入法开发解析,介绍安卓输入法开发框架和基本流程。
  • Android 开发自定义字体 库开发 输入法框架 研究 android 模拟器root权限获得 关于android模拟器root权限获取的研究 1:开发目的:基于android 系统/system/fonts/字体库添加与替换,字体库为蒙古字体库,为内蒙...
  • 本文字数:5191字预计阅读时间:20分钟目录:1导读;2Android 输入法开发简介及流程;3斗图 APP 开发介绍;4斗图 APP 功能优化;5总结。01导读微信斗图的应用有很多,...
  • 社会在发展,科技在进步。曾经交通不畅信息闭塞,如今通过互联网络我们足不出户便闻天下事;...我国作为智能手机用户的大国,如何提高中文输入的速率、优化输入法字符的输入方式已经成为急需解决的问题。
  • 本文主要介绍了C#实现输入法的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧
  • iOS输入法开发(Swift)

    千次阅读 2016-01-26 10:38:31
    我会复习一下有关键盘扩展的内容,然后通过使用iOS 8中的新应用扩展API的设计一个摩斯码的输入法。完成这个教程大约需要花费20分钟。完整代码   概览 通过使用自定义输入法替换系统输入法,用户可以实现...
  • 2、Android 输入法开发简介及流程; 3、斗图 APP 开发介绍; 4、斗图 APP 功能优化; 5、总结 1、导读 微信斗图的应用有很多,但大部分都是通过微信分享来实现的,需下载 APP,下载表情并分享到微信联系人,操作...
  • Android输入法开发之API浅析

    千次阅读 2016-06-14 18:38:14
    InputMethodServiceInputMethodService是整个输入法框架的核心,我们要写一个输入法,最核心的就是继承InputMethodService。 之后我们要重写几个重要的方法: onInitializeInterface()看名字就知道,他是在初始化...
  • 相当不错的例子 可以在前端实现中文输入法,体验的时候请把本机输入法调整为英文
  • ibus输入法开发记录:(二)引擎engine引擎engine介绍引擎类构造引擎接入、初始化和销毁宏定义G_DEFINE_TYPE引擎注册:class_init引擎初始化init和销毁destroy引擎使用引擎接入 引擎engine介绍 ibus的引擎(engine)...
  • android 输入法开发

    2015-01-10 13:41:16
    从SDK 1.5版本以后,Android就开放它的IMF(Input Method Framework),让我们能够开发自己的输入法。而开发输入法最好的参考就是Android自带的Sample-SoftKeyboard,虽然这个 例子仅包含英文和数字输入,但是它本身...
  • Qt实现中文输入法面板,适合嵌入式设备输入,也能在windows上跑,效果还不错,输入核心有两种,一种是google的内核一种是我基于数据库实现的。体验程序:https://download.csdn.net/download/xiaoyan_yt/10634438

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,150
精华内容 17,660
关键字:

输入法开发