锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / Windows输入法开发简介和IME及TSF开发指导
服务方向
软件开发
IME升级到TSF输入法
办公财务MIS
股票
设备监控
网页信息采集及控制
多媒体
软件开发培训
Java 安卓移动开发
Java Web开发
HTML5培训
iOS培训
网站前端开发
VC++
C++游戏开发培训
C#软件
C语言(Linux)
ASP.NET网站开发(C#)
C#软件+ASP.NET网站
SOCKET网络通信开发
COMOLE和ActiveX开发
C++(Linux)
汇编和破解
驱动开发
SkinMagicVC++换肤
流媒体开发
MicroStation二次开发
计算机英语翻译
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883

Windows输入法开发简介和IME及TSF开发指导

近期完成了几个输入法项目的开发,中间的酸甜苦辣在此描述一二,给初学者指个明路,也请有业务的客户阅读本文后能爽快合作。本文分简介、基础和源代码剖析3部分。

简介

输入法在dos时代就有了,以前的中文WPS如果没输入法,也肯定没用。微软推出windows操作系统后,输入法先是以IME形式升级,现在又推出更新的TSF技术来支持平板电脑和更高版本的Windows操作系统。
输入法软件架构一般包含几个方面:界面和皮肤、IME接口函数、IME消息、配置和码表等等。输入法窗口的界面和普通的对话框不一样,初学者不一定能理解。
锐英源输入法项目的突出特点有:码表的特别高效处理机制、转换机制复杂有联想和连接处理、完善的32位系统和64位系统支持、多窗口动态界面机制、支持win7/win8/win10、完美支持PowerPoint输入和完整的配套工具。如果你开发输入法遇到上面的问题,解决不了,请找锐英源,锐英源的输入法技术指导值得信赖。

基础

This overview describes the IME and explains how to use the input method manager functions to create and manage IME windows.

  • About Input Method Editor
  • Using Input Method Editor
  • Input Method Editor Reference

本预览描述了IME,并且解释说明了如何使用输入法管理程序(IMM)函数来创建和管理IME窗口。
¨         关于输入法编辑器
¨         使用输入法编辑器
¨         输入法编辑器参考

About Input Method Editor
The input method editor relieves users of the need to remember all possible character values. Instead, the IME monitors the user's keystrokes, anticipates the characters the user may want, and presents a list of candidate characters from which to choose.

       输入法编辑器减轻了用户记住所有可能字符值的需要,取而代之,IME监控用户的击键、预见用户可能期望的字符,并且提供一个可选字符的列表,用户可以从中选择想要的字符。

By default, the IME provides an IME window through which users enter keystrokes and view and select candidates. Applications can use the input method manager (IMM) functions and messages to create and manage their own IME windows, providing a custom interface while using the conversion capabilities of the IME.

       默认情况下,IME提供了一个IME窗口,通过这个窗口,用户可以用键盘输入并且查看和选择想要的字符。应用程序可以使用输入法管理器(IMM)函数和消息来创建并且管理其自己的IME窗口(比如QQ里是五笔而Word里却是拼音),并使用IME的转换功能提供一个自定义接口(比如,英文字母到汉语的转换)。

IMM is only enabled on East Asian (Chinese, Japanese, Korean) localized Windows. On these systems, call GetSystemMetrics with SM_DBCSENABLED to determine if IMM is enabled. Note that Windows 2000 provides full-featured IME support in all localized language versions, however, that IMM is enabled only when an Asian language pack is installed. An IME-enabled application can call GetSystemMetrics with SM_IMMENABLED to determine if IMM is enabled.

       IMM只在东亚(中国,日本,韩国)本地化的Windows中才可用。在这些系统中,以SM_DBCSENABLED消息调用GetSystemMetrics函数来确定IMM是否可用。注意,Windows 2000在所有本地化版本中都提供了全功能的IME支持,然而仅在安装了亚洲语言包的时候IMM才可用。一个IME-enabled(IME可用)的程序会以SM_IMMENABLED调用GetSystemMetrics函数来确定IMM是否可用。

Status, Composition, and Candidates Windows
The status, composition, and candidates windows form the user interface for the IME. The status window indicates that the IME is open and provides the user the means to set the conversion modes. The composition window appears when the user enters text and, depending on the conversion mode, either displays the text as entered or displays converted text. The candidates window appears in conjunction with the composition window. It contains a list of "candidates" (alternative characters) for the selected character or characters in the composition window. The user can scroll through the candidates list and select the desired characters, then return to the composition window. The user can compose the desired text in this way until the composition string is finalized and the window is closed. The IME sends the composed characters to the application in the form of WM_IME_CHAR or WM_IME_COMPOSITION/GCS_RESULT messages. If the application does not process these messages, the DefWindowProc function translates them into one or more WM_CHAR messages.

       状态窗口、字母组合窗口和列选窗口构成了IME的用户界面。状态窗口指示出IME处于开启状态并且提供给用户设置转换模式的方法。字母组合窗口会在用户输入字符的时候出现,其形式基于转换模式,同时显示已经输入的字母或者是已经转换了的字符。(conversion mode转换模式=输入法,比如微软拼音、五笔字型……其实不同的输入法的本质是不同的转换规则。)列选窗口会紧挨着字母组合窗口显示。它包含了一个由“候选条目”构成的列表,此列表匹配选中字符或者是字母组合窗口中的字符。用户可以滚动列选窗口并且选择想要的字符,然后(焦点)返回到字母组合窗口。借此用户可以组合想要的文本直到字符组合成的字符串结束,窗口会关闭。IME将使用WM_IME_CHAR或 WM_IME_COMPOSITION/GCS_RESULT消息把组合好的字符发送给窗体中的应用程序。如果应用程序没有处理这些消息,DefWindowProc函数会把它们翻译成一条或多条WM_CHAR消息。

By default, the system automatically creates and manages status, composition, and candidates windows for all windows that require text input. For many applications, this default processing is sufficient. These applications rely entirely on the system for IME support and are said to be IME-unaware because they are unaware of the many tasks the system carries out to manage the IME windows.

       默认情况下,系统会为所有要求输入文本的窗口自动生成并管理状态窗口、字母组合窗口和列选窗口。对于许多程序,这一默认处理已经足够了。这些完全依赖于系统提供IME支持的应用程序称为IME-unaware(IME无感知)程序,原因在于它们对系统为管理IME窗口所完成的诸多任务毫无感觉。

An IME-aware application, on the other hand, participates in the creation and management of IME windows. Such applications control the operation, position, and appearance of the default windows by sending messages to and by intercepting and processing messages intended for these windows. In some cases, applications create their own IME windows and provide complete processing for their custom status, composition and candidates windows.

       相反,一个IME-aware(IME感知)程序会参与IME窗口的创建与管理。例如程序可能通过发送或截取消息并且有目的地对这些(IME)窗口消息进行处理,来控制默认(IME)窗口的选项、位置和外观。有些情况下,应用程序会创建它们自己的IME窗口并且对其自定义的状态、字母组合和列选窗口提供完全的控制处理。
IME Window Class
The "IME" window class is a predefined system global class that defines the appearance and behavior of the standard IME windows. The class is similar to common control classes in that you create a window of this class by using theCreateWindowEx function. Like static controls, an IME window does not respond to user input by itself. Instead, it notifies the IME of user input actions and processes control messages sent to it by the IME or applications to carry out a response to the user action.
IME-aware applications sometimes create their own IME windows using the IME class. This allows the application to take advantage of the default processing of the IME window while having control of the positioning of the window.

“IME”窗口类是一个预定义的系统全局类,它定义了标准IME窗口的外观与行为。在使用CreateWindowEx函数生成窗口时,这个类与普通的控件类很相似。像静态控件一样,IME窗口类自己不响应用户的输入。取而代之,它将用户的输入操作通知给IME并且处理由IME或者应用程序为了响应用户行为而发送给它的控制消息。
       IME感知类型的应用程序有时会应用IME类创建自己的IME窗口。这样当程序包含有窗口定位控件时就允许应用程序利用IME窗口的默认数据处理。

IME Messages
The system sends IME window messages to the window procedure of the application when certain events occur that affect the IME windows. For example, the system sends the WM_IME_SETCONTEXT message to the application when a window is activated. IME-unaware application pass these messages to the DefWindowProc function which sends them to the corresponding default IME window. IME-aware applications either process these messages or forward them to their own IME windows.
You can direct an IME window to carry out a command, such as change the position of composition window, by using the WM_IME_CONTROL message. The IME notifies the application about changes to the composition string by using theWM_IME_COMPOSITION message and about general changes to the status of the IME windows by sending the WM_IME_NOTIFY message.

       当某些能影响IME窗口的事件发生时,系统将向应用程序的窗口过程(window procedure)发送IME窗口消息。例如:当(应用程序的)窗口激活时系统将向应用程序WM_IME_SETCONTEXT消息。IME无感知类型的应用程序会把这些消息传递给DefWindowProc 函数,函数会把它们发送给相应的IME窗口。IME感知型的应用程序也会将这些消息或者把这些消息传递给自己的IME窗口。
       你可以直接控制IME窗口来执行命令,诸如可以用WM_IME_CONTROL消息来改变字母组合窗口(composition window,见上文)的位置。IME会使用WM_IME_COMPOSITION消息来通知应用程序关于字母组合字符串的变化,或用WM_IME_NOTIFY消息来通知关于IME窗口状态的常规改变。

Input Context
An input context is an internal structure, maintained by the IME, that contains information about the status of the IME and is used by IME windows. By default, the system creates and assigns an input context to each thread. Within the thread, this default input context is a shared resource and is associated with each newly created window.

       输入上下文(Input context)是一个内置结构,由IME来维护,它包含了IME窗口所使用的有关IME状态的信息。默认情况下,系统会为每一个线程创建并指定一个输入上下文。在线程中,这个默认的输入上下文是一个共享资源,并且将会与每个新建窗口关联。

To retrieve or set information in the IME, an application must first retrieve a handle to the input context associated with a specified window. You retrieve the handle by using the ImmGetContext function. You can use the retrieved handle in subsequent calls to the input method manager functions to retrieve and set IME values, such as the composition window style, the composition style, and the status window position. Once you have finished using the context, you must release it using the ImmReleaseContext function.

       要在IME中检索或设置信息,应用程序必须首先获得一个与指定窗口相关联的输入上下文的句柄。你可以通过ImmGetContext函数来获得这个句柄。在随后的输入法管理函数调用中,你可以使用这个句柄来检索和设置IME的值,诸如字母组合窗口的风格、字母组合的风格以及状态窗口的位置等。一旦你完成了上下文的使用,你就必须使用ImmReleaseContext函数来释放它。

Because the default input context is a shared resource, any changes you make to it apply to all windows in the thread. However, you can override this default behavior by creating and associating your own input context to one or more windows of the thread. The changes you make to your own input context apply only to the windows with which it is associated.

       因为默认的输入上下文是一个共享资源,你对它的任何改变都将应用于线程中的所有窗口。不过,你可以通过为线程中的一个或多个窗口生成并关联自己的输入上下文的方法来重写默认的行为。(不过,你也可以重写默认的行为,方法是为线程中的一个或多个窗口生成并关联自己输入上下文。)你对自己的输入上下文所做的改动将仅应用于与其相关的窗口上。

You can create an input context by using the ImmCreateContext function. To assign the context to a window, call the ImmAssociateContext function. This function returns a handle to the previously associated input context. If you have not associated an input context with the window before, the returned handle is for the default input context. Typically, you save this handle and later reassociate it with the window when you no longer want to use your own input context.
Once an input context is associated with a window, the system automatically selects that context when the window is activated and receives the input focus. The style and other information in the input context affects subsequent keyboard input for that window, determining whether and how the IME operates.
You must destroy any input context you create before terminating your application. First, you must remove the input context from any association it has with windows in the thread by using the ImmAssociateContext function. Then, call theImmDestroyContext function.

       你可以用调用ImmCreateContext函数来创建一个输入上下文。要把输入上下文分配给一个窗口,需要调用ImmAssociateContext函数。这个函数将返回一个句柄,这个句柄是先前与窗口关联的输入上下文的句柄。如果先前没有输入上下文与些窗口相关联,函数将返回的句柄将是默认输入上下文(的句柄)。通常,你需要保存这个句柄(默认句柄),当你不想再使用自己的输入上下文时,再把它与窗口重新关联上。
       在一个输入上下文与一个窗口关联后,当窗口被激活时并且接受输入焦点时,系统会自动选择那个上下文。输入上下文中的格式(style)和其它信息会影响此窗口随后的键盘输入——决定IME是否和如何操作。
       在结束应用程序之前,你必须销毁所有你创建的输入上下文。首先,你必须使用ImmAssociateContext函数从线程中所有与之有关联的窗口上移除输入上下文。然后,ImmDestroyContext函数。
Composition String
The composition string is the current text in the composition window. This is the text that the IME converts to final characters. Each composition string consists of one or more clauses, where a clause is the smallest combination of characters that the IME can convert to a final character. To get and set the composition string, call the ImmGetCompositionString and ImmSetCompositionString functions.
As the user enters text in the composition window, the IME tracks the status of the composition string. This status includes attribute information, clause information, typing information, and cursor position. You can retrieve the composition status by using the ImmGetCompositionString function.
In the attribute information array, all characters of one clause must have the same attribute. The attribute information is an array of 8-bit values that specifies the status of characters in the composition string. There is one value for each byte in the string, including one byte each for the lead and second bytes of any double-byte characters in the string. For each value in the array, bits 0 through 3 can be one combination of the following values.
       字母组合字符串(composition string)是指字母组合窗口中的当前文本。这是将被IME转换为最终字符的文本。每个字母组合字符串由一个或多个子串组成(clauses),子串是IME能转换成最终字符的最小字符组合。要获取或设置字母组合字符串,调用ImmGetCompositionString 和ImmSetCompositionString函数。
       当用户在字母组合窗口中输入文本时,IME会跟踪字母组合字符串的状态。这些状态包括属性信息、子串信息、录入信息和子串的位置。你可以通过使用ImmGetCompositionString函数来检索字母组合的状态。
       在属性信息数组中,同一个子串中的所有字母都必须具有相同的属性。属性信息是一个由8位值组成的数组,用于确定字母组合字符串中的字符。字符串中的每个字节都对应有一个值,其中,字符串中每个双字节字符的第一和第二字节也都对应的一个值。数组中的每个值,从第0位到第3位可以是下面各值的组合:

Value(值)

Meaning(含意)

ATTR_INPUT

Character being entered by the user. It is yet to be converted by the IME.
用户输入的字符。它将被IME转换。

ATTR_INPUT_ERROR

Character is an error character and cannot be converted by the IME. For example, some consonants cannot be put together.
字符是一个错误的字符,不能被IME所转换。使用某些辅音字母不能放在一起。

ATTR_TARGET_CONVERTED

Character converted by the IME. The user has selected this character and the IME has converted it.
被IME所转换了的字符。用户已经选择了这个字符并且IME已经将其转换。

ATTR_CONVERTED

A converted character. The IME has already converted this character.
一个已经转换了的字符。IME已经将其转换。

ATTR_TARGET_NOTCONVERTED

Character being converted. The user has selected this character but the IME has not yet converted it.
正在转换中的字符。用户已经选择了这个字符,但是IME还没有转换它。

ATTR_FIXEDCONVERTED

Characters that will not be converted. The IME will not convert these characters anymore.
不能被转换的字符。IME将不能再对其转换。

All other values are reserved. In Japanese, any unconverted character having the ATTR_INPUT attribute is a Hiragana, Katakana, or alphanumeric character. In Korean, this character is a Hangeul character that is not converted by IME yet. In Traditional and Simplified Chinese, each IME may limit its character in some range.

       其它值(大概是指8位中的)将被保留。在日文中,任何拥有ATTR_INPUT属性而不能被转换的字符都是一个平假名、片假名是数字字母。在韩文中,这样的字符是一个韩文字符,它也不能被IME所转换。在传统(也就是繁体)和简体中文中,各个IME(大概是指各个输入法)会以自己的范围内限制它的字符。

The clause information is an array of 32-bit values that specifies the positions of the clauses in the composition string. There is one value for each clause and a final value that specifies the length of the full string. Each value in the array specifies the offset, in bytes, from the beginning of the string to the clause. The first value is always 0 because the first clause always starts at the beginning of the string. For example, if a string has two clauses, the clause information has three values: the first value is 0, the second value is the offset of the second clause, and the third value is the length of the string. For Unicode, the position of a clause is the position counted in Unicode characters, and the length of a string is the size in Unicode characters.

       子串信息是一个32位值的数组,用于确定子串在字母组合字符串中的位置。每个子串对应一个值,最后一个值确定整个字母组合字符串的长度。数组中的每个值在字节级别上(以字节为单位)确定了子串由字符串算起的偏移量。第一个值总是0,因为第一个子串总是从字符串的起点开始。例如,如果字符串有两个子串,子串消息(数组)就会有三个值:第一个值是0,第二个值是第二个子串的偏移量,第三个值是字符串的长度。对于Unicode,子串的位置是用Unicode字符计算出的位置,并且字符串的长度也是以Unicode字符计数。

The typing information is a null-terminated character string representing the characters entered at the keyboard.
The cursor position is a value indicating the position of the cursor relative to the characters in the composition string. The value is the offset, in bytes, from the beginning of the string. If this value is 0, the cursor is immediately before the first character in the string. If the value is equal to the length of the string, the cursor is immediately after the last character. If –1, the cursor is not present. For Unicode, both position and length are measured in Unicode characters.

       录入信息是一个无终结字符(null-terminated character)字符串,代表由键盘输入的字符。光标位置(cursor position)是一个值,它指出光标相对于字母组合字符串中字符的位置。此值是个以字节计算的偏移量,从字符串的起点算起。如果值与字符串的长度相等,光标恰好处在最后一个字符的后面。如果值为-1,意味着没有光标(光标不显示)。对于Unicode,位置和长度都是以Unicode字符来度量的。

You can set the composition string or elements of the composition status by using the ImmSetCompositionString function. To ensure that the composition window updates its appearance based on these changes, the function allows you to send a notification message to the window. Applications that set a combination of composition status elements typically set the fNotify parameter to FALSE for all but the last call to this function so that only one notification message is generated for the composition window.
Finally, the edit control supports two messages for changing the IME's handling of composition strings. For more information, see EM_GETIMESTATUS and EM_SETIMESTATUS. For more information on the edit control, see Edit Controls.

       你可以使用ImmSetCompositionString函数来设置字母组合字符串或者其中元素的属性。为了确保字母组合窗口已经根据这些改变更新了它的外观显示,函数允许你向窗口发送一个通知消息。设定字母组合字符串状态元素组合的应用程序,默认情况下会把所有对此函数调用中的fNotify参数设置为FASLE,除了最后一个调用,所以对字母组合窗口只会生成一个通知消息。
       最后,编辑控件还支持两个IME的字母组合字符串处理消息。更多信息,参见EM_GETIMESTATUS 和 EM_SETIMESTATUS。更多有关编辑控件的信息,参见Edit Controls。
Candidate Lists
A candidate list is a CANDIDATELIST structure consisting of an array of strings that specifies the characters or character strings that the user may choose from. You can retrieve the candidate lists by using the ImmGetCandidateListCount andImmGetCandidateList functions.

       备选列表是一个CANDIDATELIST结构,这个结构由一个列出用户可从中选取字符(例如汉字)或者字符串(例如词)的字符串数组组成。你可以用ImmGetCandidateListCount 和ImmGetCandidateList函数来检索备选列表中。

Hot Keys
Hot keys give the user a way to quickly change the input mode of the IME or to switch to another IME. Although applications cannot add hot keys to the system, they can initiate the same action as a hot key by using the ImmSimulateHotKeyfunction.
The HexToUnicode IME also permits conversion between hexadecimal and Unicode characters. For an explanation, see HexToUnicode IME.

       快捷键(热键)为用户提供了快速改变IME输入状态(例如中/文切换)或选择别的IME(例如从拼音换成五笔)的途径。尽管应用程序不能给系统添加快捷键,但是它可以通过使用ImmSimulateHotKey函数模仿快捷键效果,来启动相同的操作任务。
       HexToUnicode IME还允许十六进制字符与Unicode字符之间的转换。解释请参见HexToUnicode IME。

HexToUnicode IME
Rich Edit 3.0 supports the HexToUnicode IME, which allows a user to convert between hexadecimal and Unicode characters by using hot keys in one of two ways.
In the first method, the user types the character code in hexadecimal and then types ALT+X. The IME replaces the hexadecimal digits preceding the insertion point with the Unicode character. If the current font does not support the character code, an appropriate font is chosen that does support it. To convert from Unicode to hexadecimal, type SHIFT+ALT+X. This replaces the Unicode character that precedes the insertion point with the hexadecimal digits. In particular, this allows you to determine the character that is indicated by a "missing glyph" indicator. If the hexadecimal character code immediately follows some legitimate (noncharacter) hexadecimal characters, select the specific digits that you want to convert before typing ALT+X. A problem with this first method is that ALT+X is sometimes used as a key combination for the exit command (that is, eXit). For example, in Microsoft Office, this only happens as an option of the File menu.
The second method involves the number pad. Here the user types ALT+NumPad numbers (with values greater than 255) to enter Unicode characters using decimal values. This method is not as useful as the first method because you cannot see what hexadecimal digits you typed. Also, you cannot correct them except by reentering them all again.

       Rich Edit 3.0支持HexToUnicode IME,它允许用户实现十六进制字符和Unicode字符之间转换,何种转换可用快捷键指定。
       第一个方法中,用户在十六进制模式下输入字符然后输入Alt+X键。IME会用Unicode字符取代插入点前的十六进制编码。如果当前字体不支持此字符的编码,则会选用一个能够支持它的合适字体。要将Unicode字符转换成十六进制字符,输入Shift+Alt+X键即可。这一操作会将插入点前的Unicode字符取代为十六进制编码。特殊情况下,这一操作允许你自己决定由“缺失字形”指示符所指示的字符。如果十六进制字符代码后紧跟着某些十六进制非字符的代码,那么在输入Alt+X之前应该选择一个你想转换成的特殊字符。第一个方法的问题在于Alt+X往往被当做退出程序的组合键(也就是,eXit)来使用。例如,在Microsoft Office中,它将执行与File菜单中选项(退出选项)相同的功能。
       第二个方法涉及数字键盘。用户可以通过Alt+数字键盘数字(数字必须大于255)的方法用十进制值来输入Unicode字符。因为你看不见你输入的十六进制编码值,这个方法比起第一个方法就稍有逊色了。而且,要修改就要重新输入,别无选择。

代码剖析

锐英源搜集了大量的输入法源代码,从IME形式到TSF形式都很多,欢迎交流。这里列出一个sinstar的输入法的核心代码,剖析一二。

ImeToAsciiEx

/****************************************************************************************************************/
/* function:应用程序调用这个接口来进行输入上下文的转换,输入法程序在这个接口中转换用户的输入                                       */
/* UINT uVKey:键值,如果在ImeInquire接口中为fdwProperty设置了属性IME_PROP_KBD_CHAR_FIRST,则高字节是输入键值          */
/* UINT uScanCode:按键的扫描码,有时两个键有同样的键值,这时需要使用uScanCode来区分                                                               */
/* CONST LPBYTE lpbKeyState:键盘状态,包含256键的状态                                                                                                                              */
/* LPDWORD lpdwTransKey:消息缓冲区,用来保存IME要发给应用程序的消息,第一个双字是缓冲区可以容纳的最大消息条数   */
/* UINT fuState:Active menu flag(come from msdn)                                                                                                                                      */
/* HIMC hIMC:输入上下文                                                                                                                                                                                                   */
/* return : 返回保存在消息缓冲区lpdwTransKey中的消息个数                                                                                                                     */
/****************************************************************************************************************/
UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC)
{
LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
UINT uMsgCount=0;
if(lpIMC)
{
LPCONTEXTPRIV lpCntxtPriv=(LPCONTEXTPRIV)ImmLockIMCC(lpIMC->hPrivate);
BYTE byInput=LOBYTE(uVKey);//获取VK
BOOL bHandle=FALSE;
//用户词典快捷键
if(lpbKeyState[VK_CONTROL] & 0x80 && lpbKeyState[VK_SHIFT] & 0x80)
{
if(byInput==g_SettingsG.byHotKeyQuery)
{
UserDict_Input(lpIMC->hWnd);
bHandle=TRUE;
}else
{
bHandle=Plugin_HotkeyProcess(uVKey,uScanCode);
}
}
//首先使用VK处理快捷键及重码翻页键
if(!bHandle && lpbKeyState[VK_CONTROL] & 0x80 )
{//处理快捷键
//此处省略
}
if(!bHandle && lpCntxtPriv && lpCntxtPriv->sCandCount && lpCntxtPriv->sbState!=SBST_SENTENCE)
{//处理重码
//此处省略
}
//处理拼音的音节移动
if(!bHandle && g_CompMode==IM_SPELL)
{
//此处省略
}
byInput=HIBYTE(uVKey);         //取得按键的ASCII码
if(byInput==VK_RETURN && lpbKeyState[VK_SHIFT]&0x80)
{
bHandle=KeyIn_RepeatInput(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}
if(!bHandle && lpCntxtPriv && byInput)
{
if(lpCntxtPriv->inState==INST_CODING)
{//先做状态转换前处理
BOOL bReadyEn=FALSE;
BOOL bReadyDgt=FALSE;
if(lpCntxtPriv->sbState==SBST_NORMAL)
{
if(g_CompMode==IM_SPELL)
{
if(lpCntxtPriv->bySyllables==1 && lpCntxtPriv->spellData[0].bySpellLen==0)
{
bReadyEn=TRUE;
bReadyDgt=TRUE;
}
}else
{
if(lpCntxtPriv->cCompLen==0)
{
bReadyEn=TRUE;
bReadyDgt=TRUE;
}
}
}else if(lpCntxtPriv->sbState==SBST_ASSOCIATE)
{
bReadyEn=TRUE;
bReadyDgt=TRUE;
if((g_SettingsG.byAstMode==AST_CAND ||(g_SettingsG.byAstMode==AST_ENGLISH &&(lpbKeyState[VK_CONTROL]&0x80))) && lpCntxtPriv->sCandCount)
bReadyDgt=FALSE;
}
if(g_bTempSpell && (bReadyEn || bReadyDgt) && (isdigit(byInput) || isupper(byInput)))
{//temp spell mode
if(g_SettingsG.bSoundAlert) SoundPlay("error");
ImmUnlockIMCC(lpIMC->hPrivate);
ImmUnlockIMC(hIMC);
return 0;
}
if((bReadyEn || bReadyDgt) && g_bTipShow) //关闭tip
g_bTipShow=FALSE;
if(bReadyEn && byInput>='A' && byInput<='Z')
{//大写输入,则切换到英文状态
ClearPrivateContextEx(lpCntxtPriv,CPC_ALL);
if(g_SettingsL.bEnglish)
{
//此处省略
}
}else if(bReadyDgt && byInput>='0' && byInput<='9')
{//数字输入,进入数字输入状态
ClearPrivateContextEx(lpCntxtPriv,CPC_ALL);
lpCntxtPriv->inState=INST_DIGITAL;
Plugin_StateChange(g_CompMode,lpCntxtPriv->inState,lpCntxtPriv->sbState,g_bTempSpell);
MyGenerateMessageToTransKey(lpdwTransKey,&uMsgCount,WM_IME_NOTIFY,IMN_PRIVATE,IMN_PRIV_CLOSEINPUTWND);
}
}
if(lpCntxtPriv->inState==INST_CODING)
{
if(lpCntxtPriv->sbState==SBST_NORMAL)
{//编码输入
if(g_CompMode==IM_SPELL)
{//拼音状态
if(lpCntxtPriv->bPYBiHua)
{//笔画辅助输入,不支持万能键
BOOL bInputKey=FALSE;
if(LOBYTE(uVKey)>=VK_NUMPAD1&&LOBYTE(uVKey)<=VK_NUMPAD5)
{//小键盘输入
byInput=LOBYTE(uVKey);
bInputKey=TRUE;
}else
{//设置的转换键
int i;
for( i=0;i<5;i++)
{
if(g_SettingsG.byLineKey[i]==byInput)
{
byInput=VK_NUMPAD1+i;
bInputKey=TRUE;
break;
}
}
if(byInput==VK_ESCAPE || byInput==VK_BACK) bInputKey=TRUE;
}
bHandle=KeyIn_PYBiHua_ChangComp(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
if(!bHandle) bHandle=KeyIn_Spell_InputText(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}else
{
bHandle=KeyIn_Spell_Normal(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}
}else
{
bHandle=KeyIn_Code_Normal(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}
}else if(lpCntxtPriv->sbState==SBST_ASSOCIATE)
{//联想状态
bHandle=KeyIn_All_Associate(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}else if(lpCntxtPriv->sbState==SBST_SENTENCE)
{//句子状态
bHandle=KeyIn_All_Sentence(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
if(!bHandle) KeyIn_Code_Symbol(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}
}else if(lpCntxtPriv->inState==INST_ENGLISH)
{//英文单词状态
bHandle=KeyIn_Code_English(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}else if(lpCntxtPriv->inState==INST_DIGITAL)
{//数字输入状态
bHandle=KeyIn_Digital_ChangeComp(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}else if(lpCntxtPriv->inState==INST_USERDEF)
{//用户自定义输入状态
bHandle=KeyIn_UserDef_ChangeComp(hIMC,lpIMC,lpCntxtPriv,byInput,lpbKeyState,lpdwTransKey,&uMsgCount);
}else if(lpCntxtPriv->inState==INST_LINEIME)
{//笔画输入状态
//此处省略
}
if(!bHandle && g_SettingsG.bSoundAlert) SoundPlay("error");
}
ImmUnlockIMCC(lpIMC->hPrivate);
ImmUnlockIMC(hIMC);
}
return (uMsgCount);
}

Plugin_HotkeyProcess

插件热键处理
BOOL      Plugin_HotkeyProcess(UINT uVKey,UINT uScanCode)
{
BOOL bRet=FALSE;
if(g_spInfo.funHotkeyProcess) bRet=g_spInfo.funHotkeyProcess(uVKey,uScanCode);
return bRet;
}
funHotkeyProcess和函数指针技术有关联,加载了其它DLL的函数来执行,其它DLL就是插件了。

KeyIn_PYBiHua_ChangComp

//拼音的笔画辅助重码选择状态:输入编码
BOOL KeyIn_PYBiHua_ChangComp(HIMC hIMC,LPINPUTCONTEXT lpIMC,LPCONTEXTPRIV lpCntxtPriv,BYTE byInput,
CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT *pMsgCnt)
{
BOOL bRet=FALSE;
int nLen=strlen(g_szPYBiHua);

if(byInput == VK_BACK)
{
if(nLen>0)
{
g_szPYBiHua[--nLen]=0;
bRet=TRUE;
}else
{//退出笔画输入状态
if(lpCntxtPriv->bPYBiHua) lpCntxtPriv->bPYBiHua=FALSE;
//生成消息
MyGenerateMessageToTransKey(lpdwTransKey,pMsgCnt,WM_IME_NOTIFY,IMN_PRIVATE,IMN_PRIV_UPDATEINPUTWND);
return TRUE;
}
}else if(byInput>=VK_NUMPAD1 && byInput<=VK_NUMPAD6)
{
if(nLen<50)
{
g_szPYBiHua[nLen++]=byInput-VK_NUMPAD1+'1';//输入键码转换到全局变量里
g_szPYBiHua[nLen]=0;
}
bRet=TRUE;
}else if(byInput==VK_ESCAPE)
{
lpCntxtPriv->bPYBiHua=FALSE;
g_szPYBiHua[0]=0;
//生成消息
MyGenerateMessageToTransKey(lpdwTransKey,pMsgCnt,WM_IME_NOTIFY,IMN_PRIVATE,IMN_PRIV_UPDATEINPUTWND);
return TRUE;
}
if(bRet)
{
char *pszWordList=(char*)malloc(lpCntxtPriv->sCandCount*2);
short i;
for(i=0;i<lpCntxtPriv->sCandCount;i++)
{
LPBYTE pbyCand=lpCntxtPriv->ppbyCandInfo[i];
memcpy(pszWordList+i*2,pbyCand+2,2);
}
//候选进行排序处理
if(ISComm_SortWordByBiHua(g_szPYBiHua,nLen,pszWordList,lpCntxtPriv->sCandCount)==ISACK_SUCCESS)
{
PMSGDATA pData=ISComm_GetData();
for(i=0;i<lpCntxtPriv->sCandCount;i++)
{
LPBYTE pbyCand=lpCntxtPriv->ppbyCandInfo[i];
memcpy(pbyCand+2,pData->byData+i*2,2);//加入到候选
}
memcpy(lpCntxtPriv->szWord+lpCntxtPriv->byCaret,pData->byData,2);//自动选择第一个重码
lpCntxtPriv->bySelect[lpCntxtPriv->byCaret]=1;                                     //设定为自动选择,不允许自动修改
lpCntxtPriv->sCurCandPage=0;
}else
{
if(g_SettingsG.bSoundAlert) SoundPlay("error");
}
free(pszWordList);
//生成消息
MyGenerateMessageToTransKey(lpdwTransKey,pMsgCnt,WM_IME_NOTIFY,IMN_PRIVATE,IMN_PRIV_UPDATEINPUTWND);
}
return bRet;
}

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内