1.TSF输入接口

IMM-IME架构成熟,稳定,易于实现,在Windows中被广泛使用,甚至在Linux曾大量使用的中文输入接口SCIM中也可以看到IMM-IME的影子。但是由于IMM-IME在操作权限管理上有些欠缺,输入法文件的扩展名是IME,但是实质是DLL,使得恶意软件通过该接口挂接到应用程序成为可能。为了提高安全性、规范性,Microsoft设计了基于COM(Component Object Model)的TSF(Text Services Framework)接口。

TSF是文本服务框架的简称,基于TSF的每一个输入法IME都是COM组件。图1显示了TSF与应用程序之间的关系, TSF管理器由操作系统提供并且不可被替换,它是应用程序和IME之间的中介。基于安全的考虑,IME也不能直接和应用程序打交道,TSF将输入事件传达给IME并在用户选择字符后接受从 IME 返回的输入字符。与IMM-IME类似,TSF中的IME同样可以由第三方开发。

Windows 8/8.1和10开始提供了Metro界面和传统桌面两种工作模式,在传统桌面的工作模式中同时支持IMM-IME和TSF两种架构,但在Metro界面中就只支持TSF架构的输入法了,因此基于TSF的输入法必将淘汰IMM-IME结构的输入法。

支持TSF的应用程序可以在不用感知文本设备的前提下,接受从不同文本设备(键盘、手写、语音等)来源的文本输入。此外,TSF的一个重要优势是对输入法权限的管控程度远远高于IMM-IME,大大有利于系统的安全性。

image.png

2.COM (Component Object Class)

COM提供了一种在不同的应用程序和语言之间共享二进制代码的规范,COM本身的设计是和具体程序设计语言无关,因此不依赖任何语言层面的特征。使用COM编写的二进制模块必须适应与支持一些特定的数据结构,COM规范同样也定义COM对象在内存中应该如何被组织与安排。

COM基本术语

1)接口interface:接口可以看成是包含一组待实现方法的类。接口名通常以I开头,在C++中,接口就是包含纯虚函数的抽象类。

2)组件对象类coclass:它的全称是component object class,coclass用来实现接口。一个COM对象是coclass类在内存中的一个实例。

3) 组件服务器COM Server:含有一个或多个coclass的二进制模块,可以是DLL文件也可以是EXE文件。

4)Registration:向Windows注册、登记COM Server的位置和入口。

5)Unregistration:是Registration的逆过程,从Windows中移除掉这个登记。

6)GUID:它的全称是globally unique identifier,是一个128位的无符号数,用于唯一标记接口和组件对象类,有时GUID也被称为UUID(universally unique identifier)。一个coclass的class ID称为CLSID;一个interface的interfaceID称为IID。

基接口(base interface):IUnknown

每一个COM接口都要从IUnknown接口继承,IUnknown接口提供了两个非常重要的特性:生存期控制和接口查询。IUnknown接口是所有COM接口的根。该接口用C++描述如下:

class IUnknow
{
public:
      virtual  HRESULT    _stdcall Queryface(const IID& iid,void **ppv) = 0;
      virtual  ULONG       _stdcall AddRef() = 0;
      virtual  ULONG       _stdcall  Release() = 0;
};

可见这个接口有三个方法: QueryInterface、AddRef和Release。QueryInterface用于在获取某个COM的一个接口指针后,查询该COM的其它接口指针。AddRef用于增加引用计数,Release用于减少引用计数。

3.物理键盘与软键盘

由于Windows 8/10的手持设备通常没有物理键盘,因此触控键盘成为了TSF输入法必要组成部分。Windows 8的TSF触摸键盘支持七种布局,其中三种属于经典布局,四种属于触摸优化布局。经典布局的外观和行为和物理键盘更加相似,四种优化布局是分别针对朝鲜语、日语、简体中文和繁体中文而设计的。图2就是在简体中文优化布局下的数字触控键盘。

image.png

ITfFnGetPreferredTouchKeyboardLayou接口的函数GetLayout是一个虚函数,可以通过重写该函数实现为TSF输入法指定触控键盘布局,但是TSF不允许用户自定义自己的触控键盘布局。表1列出了GetLayout指定触控键盘的参数,具体细节可以到MSDN中查询。

七种触控键盘布局

布局定义

语系

TKBL_CLASSIC_TRADITIONAL_CHINESE_PHONETIC

0x0404

CHT

TKBL_CLASSIC_TRADITIONAL_CHINESE_CHANGJIE

0xF042

CHT

TKBL_CLASSIC_TRADITIONAL_CHINESE_DAYI

0xF043

CHT

TKBL_OPT_JAPANESE_ABC

0x0411

JPN

TKBL_OPT_KOREAN_HANGUL_2_BULSIK

0x0412

KOR

TKBL_OPT_SIMPLIFIED_CHINESE_PINYIN

0x0804

CHS

TKBL_OPT_TRADITIONAL_CHINESE_PHONETIC

0x0404

CHT

4.TSF输入接口

TSF设计了十余个接口,表2中列出了最主要的输入接口,编写TSF的输入法需要继承并实现这些接口。

62 TSF输入法接口

接口

说明

ITfTextInputProcessorEx

TSF管理器通过该接口激活或冻结输入法。

ITfThreadMgrEventSink

用于接收线程管理器的事件通知。

ITfKeyEventSink

输入法用来接收和拦截键盘与焦点通知。

ITfCompositionSink

处理输入码编辑被终止的情况。

ITfDisplayAttributeProvider

TSF管理器通过该接口获取独立显示对象

ITfActiveLanguage-
   ProfileNotifySink

输入法被选择。

ITfThreadFocusSink

线程获取或者失去焦点

ITfFunctionProvider

用于枚举提供的函数对象。

ITfFnGetPreferredTouch-
   KeyboardLayout

用于选择输入法所要使用的虚拟键盘的布局。

ITfTextEditSink

支持实现包含读写权限的编辑Session

TSF输入法的类需要继承上述的接口,并对接口中的必要函数进行定制与实现。下面对其中最重要的ITfKeyEventSink进行简要介绍,表3列出了该接口的主要函数以及说明。

3 ITfKeyEventSink接口的函数说明

函数

函数说明

OnSetFocus

当输入法得到或者失去键盘焦点时自动调用

OnPreservedKey

当发生系统保留键事件。

OnTestKeyDown 

当一个键盘KeyDown事件发生时,调用本函数来判断输入法是否需要一个按键。

OnKeyDown

如果OnTestKeyDown   认为需要,则调用本函数。

OnTestKeyUp

OnTestKeyDown类似

OnKeyUp

OnKeyDown类似

值得说明的是:虽然一次按键会发生KeyDownKeyUp消息,但是输入法通常只要选择处理其中一类消息。例如纵横输入法就是重点实现了OnTestKeyDownOnKeyDown两个函数。不同的输入法运行机制类似,但是对于按键的处理各有不同,因此每种输入法都需要对这两个函数深度定制。

5.TSF输入法部署

目前,64位的计算机已经成为主流,但是为了和32位的程序兼容,Windows 8/10 X64中也允许安装与运行32位程序。为了保证用户能够便捷地在不同程序中使用输入法,因此需要编译输入法的X64X86的两个版本并发布到用户计算机中,因为64位的应用程序只能使用64位的输入法,32位的程序必须使用32位的输入法。

64位的输入法可以部署到用户计算机的Windows安装文件夹下的System32子文件夹,32位的版本部署到Windows安装文件夹下的SysWOW64子文件夹。

6.TSF输入法注册

由于TSF的输入法是一个COM组件,因此注册的方法和COM组件一样,实质是在注册表HKEY_CLASSES_ROOT中建立类似如下的键:

[HKEY_CLASSES_ROOT\CLSID\{D2291A80-84D8-4641-9AB2-BDD1472C846B}]
@=纵横汉字输入法
[HKEY_CLASSES_ROOT\CLSID\{D2291A80-84D8-4641-9AB2-BDD1472C846B}\InProcServer32]
@=C:\\WINDOWS\\system32\\CKCIme.dll
ThreadingModel=Apartment

{D2291A80-84D8-4641-9AB2-BDD1472C846B}是一个用于区分COM组件的全球唯一ID,开发人员可以根据需要自己需要定制与修改。

32位版本的输入法在注册表注册信息如下:

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{D2291A80-84D8-4641-9AB2-BDD1472C846B}]
@=纵横汉字输入法
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{D2291A80-84D8-4641-9AB2-BDD1472C846B}\InProcServer32]
@=C:\\WINDOWS\\SysWow64\\CKCIme.dll
ThreadingModel=Apartment

但是Microsoft不建议用户直接写注册表注册输入法,而是希望大家通过调用系统提供的ITfInputProcessorProfileMgrRegisterProfile方法进行注册,该方法原型如下:

HRESULT RegisterProfile(
  REFCLSID rclsid,     //输入法服务的唯一CLSID号
  LANGID   langid,   //语系ID
  REFGUID  guidProfile,
  const WCHAR    *pchDesc,
  ULONG    cchDesc,
  const WCHAR    *pchIconFile, //图标文件名
  ULONG    cchFile,
  ULONG    uIconIndex,  //图标索引号
  HKL      hklSubstitute,
  DWORD    dwPreferredLayout,    //未使用,必须填0
  BOOL     bEnabledByDefault,
  DWORD    dwFlags
);

7.输入法的权限问题

这里的权限主要包括网络权限和文件系统访问权限。TSF输入法的权限取决于使用它的用户以及应用程序,在应用启动的时候,TSF为用户当前选择的IME加载COM组件。当IME加载到Windows应用商店应用时,它受与该应用相同的权限限制。例如:如果使用TSF输入法的应用程序不具有Internet访问权,则TSF输入法也不可以访问 Internet。因此一些IMM-IME输入法的自动通过网络升级码本数据的功能在TSF中需要重新设计。

另外大多数输入法都需要使用码本文件,码本存储了一个输入法的输入码和机内码对应关系。桌面应用程序通常对文件系统的访问权限相对高,而基于应用商店的应用对计算机文件系统的访问权限非常有限,因此为了保证码本文件总能被合法访问,建议存储到系统的“Program Files”文件夹中的子文件夹。IMM-IME输入法经常提供的在输入时自动或者手动为用户添加自定义词组的功能因为需要写文件权限,在TSF中也可能会失败。


相关推荐

基于文本服务框架(tsf)的拼音输入法研究与实现

摘要:目前的输入法大多采用输入法管理器-输入法编辑器(IMM-IME)进行开发,对于微软发布的新型输入法技术―文本服务框架(TSF)的研究一直比较滞后,该文论述了 TSF 的基本构成、主要接口、输入法

64位输入法DLL注(tsf)方案

微软两种输入法方案XP和XP以前是imm(Input Method Manager)输入方案.xp之后的系统是imm和TSF(Text Service Framework)输入方案.共存. win8

微软输入法tsf sampleime 源码分析(转载)

类:CCandidateWindow,候选字窗口CCompositionPricessorEngine,拼写引擎CSampleIME,主程序CStringRange, 一个特殊的字符串类 见于 Sam

[输入法]tsf框架中预先上屏的字符管理控制

在TSF框架中有时候我们需要通过框架上屏一些占位字符来进行定位,这时候我们就需要对预先上屏的字符进行管理,以微软的输入法为例图中红框框选出来的部分就是预先上屏的字符。在TSF框架中通过ITfRange

输入法tsf框架候选栏定位研究

在开发输入法应用的时候,我们需要让候选栏时刻跟踪输入光标的位置,来进行输入。但候选栏定位不准,一直会困扰输入法的开发者。windows老的输入法框架imm在部分场景下比如chrome应用中会定位不准,

tsf输入法

TSF 即文本服务框架的英文缩写微软官方文档(文本服务框架) https://learn.microsoft.com/zh-cn/windows/win32/tsf/text-services-fra

输入法管理器(imm)函数大全(windows ce 5.0

imm好像要被弃用了 还是研究TSF输入法 吧 ,虽然没啥鸟用了 但是还是搬运一下下吧EnumRegisterWordProc此函数是与一起使用的应用程序定义的回调函数ImmEnumRegisterW

输入法开发基础(一)

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

[输入法]Qt实现软键盘

在使用输入法的时候,为了输入一些特殊字符我们往往会用到软键盘和符号大全。符号大全和软件盘是一类程序,主要实现的就是通过界面点击向目标程序输出对应的符号。这里介绍一下如何通过QT编写软键盘类程序,实现软

快速搭建一款输入法(封装输入法引擎)

输入法最核心的是输入法引擎,输入法引擎负责加载和管理输入法配置和输入法的词库,输入法引擎对用户输入的拼音字符串进行处理并返回对应的候选列表。通过引入输入法引擎我们就可以将我们输入法的拼音串转换成对应的