最近一直在忙mac上的输入法开发,现在终于告一段落了,分享一下开发时遇到的问题和经验。
开发语言:
C,c++,object-C
开发工具:
QtCreator 2.4.1
Qt SDK 4.8.0
Xcode 3.2.6
环境搭建:
参考:
http://mobile.51cto.com/symbian-269099.htm
打开Qtcreator,创建一个新工程,build,成功,环境搭建完毕!
qt-creator-mac-opensource-2.4.1.dmg
qt-mac-opensource-4.8.0.dmg
qt-mac-opensource-4.8.0-debug-libs.dmg
输入法机制:
Mac上开发时需要遵循mac的输入法机制。以便可以调用送字的功能。(使用apple script貌似也能实现?)
下载mac输入法的官方sample,叫NumberInput_IMKit_Sample
地址:
http://developer.apple.com/library/mac/#samplecode/NumberInput_IMKit_Sample/Introduction/Intro.html
在xcode的sdk里搜索InputMethodKit
也可以找到这个sample。
下面简单说明一下mac的输入法机制。A.实现IMKInputController
继承此类后,可以重载/调用输入法的功能函数,比如送字,提交候选等,具体可以参考InputMethodKit.h(系统文件,搜索查看)
B.实现注册
//Eachinputmethodneedsauniqueconnectionname.
//Notethatperiodsandspacesarenotallowedintheconnectionname.
constNSString*kConnectionName=@"NumberInput_1_Connection";
//letthisbeaglobalsoourapplicationcontrollerdelegatecanaccessiteasily
IMKServer* server;
server=[[IMKServeralloc]initWithName:(NSString*)kConnectionNamebundleIdentifier:[[NSBundlemainBundle]bundleIdentifier]];通过指定输入法的服务名称,来通知系统,告诉他现在我的这个app是输入法程序,这样就可以调用A中的函数了。如果不通知系统,是无法使用输入法函数的。因为系统为每个输入焦点都分配一个inputSession,如果不注册,则无法获取当前的焦点id。
C.重要接口说明
A中说了要调用输入法的功能,需要继承那个IMKInputController类。
.h
#import
#import
@interface NumberInputController : IMKInputController {
NSString *m_szScript;
}
这个inputText函数就是拦截当前输入的内容(比如你按下键盘按键),来决定是否将指定的字符串发送到当前焦点上。sender是当前焦点的控件,id类型是objectC里特有的,可以指向任何类型,但是不等同于void*。
返回NO的话,按键事件不会发给焦点窗口,true的话就会发送上去。
-(BOOL)inputText:(NSString*)string client:(id)sender
{
//Return YES to indicate the the key input was received and dealt with. Key processing will not continue in that case. In
//other words the system will not deliver a key down event to the application.
//Returning NO means the original key down will be passed on to the client.
NSLog(@"inputText:%@, sender:0x%x", string, sender);
return NO;
}
commitComposition是将完成的复合结果提交上屏,里面的inserText实际上是重点函数,这个函数是将指定字符串发送到当前焦点id上。这里我将hello这个字符串发送到了当前屏幕上。
-(void)commitComposition:(id)sender
{
NSLog(@"commitComposition--sender:0x%x", sender);
[sender insertText:@" hello " replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
}
也许你会好奇这个id是怎么来的,因为inputText和commitComposition都是重写的系统函数,id是系统传进来的,如果在自己的程序里怎么能够不通过触发这两个函数来获取当前的id呢?我们来看这两个函数:
/*!
@method
@abstract Activates the input method.
*/
//激活输入法,只要将输入法放在系统目录,一有焦点切换就会进入这里
- (void)activateServer:(id)sender
{
NSLog(@"---NumberInputController activateServer sender:0x%x---", sender);
}
/*!
@method
@abstract Deactivate the input method.
*/
//和activateServer不同,deactivateServer只会在切换到别的输入法或者在焦点间切换时才会调用
- (void)deactivateServer:(id)sender
{
}
呵呵,现在是不是知道怎么做了?没错,在active的时候将sender记录下来,这样就可以全局使用啦~~~~
D.修改plist文件
CFBundleIdentifier(com.jt.inputmethod.QTestInput)
是服务的名字,这里面必须包含inputmethod字符,不然系统不会认定是输入法服务。
NSMainNibFile(MainMenu)
是nib文件的名字,注意统一。
NSPrincipalClass(NSApplication)
输入法其实也是一个application
LSBackgroundOnly(1)
这个也很重要,设定为1,这样就是一个后台运行的app,doc栏中不会有程序的icon。
InputMethodConnectionName(NumberInput_1_Connection)
输入法机制里B的那个变量,注册时使用的名字。要和代码中统一。
InputMethodServerControllerClass
InputMethodServerDelegateClass
目前注册这两个类时,这里面填写的是类名,目前使用的都是NumberInputController这个类。
至于这两个类都注册成同一个class,就是为了将这两个系统类的方法都在NumberInputController中调用。他们分别控制着系统输入法里相关的一些函数,不明白可以参考InputMethodKitOverview.pdf,实在不理解就pass吧。
tsInputMethodIconFileKey
在设置里显示的icon的文件名
CFBundleIconFile
App的icon图片文件名
E.打包发布
Pkg是mac上一般常见的安装包文件,类似setup.exe。
使用xcode自带的packageMaker工具,具体使用可以google一下。将打好依赖库的app直接拖到packageMaker里,然后Build后会生成对应的pkg文件。
编译生成的app是没有加入依赖库的(就是.pro文件里那些framework),最终发布时,程序可能要在裸机上跑,那些没有环境的设备上,因此就要将依赖库打包进来。
使用qt自带的工具,macdeployqt,该工具在Deverloper/Tools/Qt目录下。
运行时这样:
macdeployqt xxx/xxx.app –verbose=2
具体可以-h显示参数。
打依赖库:
macdeployqt xxx/xxx.app –verbose=2
打dmg
macdeployqt xxx/xxx.pkg –verbose=2 –dmg
会有错误,不用管它。
F.调试
将编译生成的app文件放在/Users/mini/library/Input Method下,然后打开系统偏好设置,进入语言和键盘,最右侧的tab里可以选择输入法,将你的输入法名字勾选即可。
随意打开一个编辑框,然后command+space切换到Qinput即可呼出输入法界面。
程序中通过NSLog,qDebug函数打印日志,调试程序。