Cocos2Dx之处理键盘输入

Cocos2Dx之处理键盘输入,第1张

概述键盘输入在Cocos2Dx分为两个部分。第一部分是一些功能键的处理:后退键和菜单键。第二部分是处理字符输入。功能键相关的代码位于cocos2dx\keypad_dispatcher。字符输入的代码位于\cocos2dx\text_input_node。 我们先看功能键的处理部分。功能键的处理比较简单,只是支持后退键和菜单键。而且功能键的支持只是对WP和Android有效。功能键部分的类关系如下图所

键盘输入在Cocos2Dx分为两个部分。第一部分是一些功能键的处理:后退键和菜单键。第二部分是处理字符输入。功能键相关的代码位于cocos2dx\keypad_dispatcher。字符输入的代码位于\cocos2dx\text_input_node。

我们先看功能键的处理部分。功能键的处理比较简单,只是支持后退键和菜单键。而且功能键的支持只是对WP和AndroID有效。功能键部分的类关系如下图所示。结构类似于触控处理。只是少了一个Delegate接口。

CCKeypadDelegate定义了两个功能键的处理接口。如果我们对处理功能键感兴趣,我们只需要继承CCKeypadDelegate,然后实现这两个接口即可。cclayer已经继承了CCKeypadDelegate。我们在定义自己的层的时候,可以重载它即可。

我们还是从WIN32的窗口过程开始,来看功能键处理接口怎么被调用到。CCEGLVIEw::WindowProc:

?
1 2 3 4 5 6 7 8 9 10 11 12 case WM_KEYDOWN: if (wParam==VK_F1||wParam==VK_F2) { CCDirector*pDirector=CCDirector::sharedDirector(); (GetKeyState(VK_LSHIFT)<0||GetKeyState(VK_RSHIFT)<0||GetKeyState(VK_SHIFT)<0) pDirector->getKeypaddispatcher()->dispatchKeypadMSG(wParam==VK_F1?kTypeBackClicked:kTypeMenuClicked); } else (wParam==VK_ESCAPE) { CCDirector::sharedDirector()->getKeypaddispatcher()->dispatchKeypadMSG(kTypeBackClicked); } break ;

CCDirector内部有一个CCKeypaddispatcher类型的成员。它就是Cocos2Dx里面负责功能键处理的唯一对象。CCDirector有接口setKeypaddispatcher来替换它默认的功能键处理对象。但现在还没有被使用到。系统将收到的功能键消息(退出键、菜单键)交给CCKeypaddispatcher的dispatchKeypadMSG处理。

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 bool CCKeypaddispatcher::dispatchKeypadMSG(ccKeypadMSGTypenMsgType) { CCKeypadHandler*pHandler=NulL; CCKeypadDelegate*pDelegate=NulL; m_bLocked= true ; (m_pDelegates->count()>0) { CCObject*pObj=NulL; CCARRAY_FOREACH(m_pDelegates,pObj) { CC_BREAK_IF(!pObj); pHandler=(CCKeypadHandler*)pObj; pDelegate=pHandler->getDelegate(); switch (nMsgType) { kTypeBackClicked: pDelegate->keyBackClicked(); ; kTypeMenuClicked: pDelegate->keyMenuClicked(); ; default : ; } } } false ; return ; }

CCKeypaddispatcher::dispatchKeypadMSG内部遍历所有的Handler,然后取出Handler包裹的Delegate,再根据功能键的类型,分别调用Delegate的keyBackClicked或keyMenuClicked。m_bLocked标记是为了分发功能键消息的过程中,又有Handler被添加进来,或者删除掉。CCKeypaddispatcher::removeDelegate和CCKeypaddispatcher::addDelegate在删除和添加时,会检查m_bLocked标记。如果现在正在分发消息,添加和删除的Delegate都先暂存起来,分别放到m_pHandlersToRemove和m_pHandlersToAdd当中。当CCKeypaddispatcher::dispatchKeypadMSG完成消息分发以后,才真正从m_pDelegates中进行删除或添加。相应的代码由于篇幅的关系,没有贴在这。

m_pDelegates中的Delegate是CCKeypaddispatcher::forceAddDelegate添加进来的。但它并不直接暴露给外部。暴露给外部的添加功能键处理Handler的接口是CCKeypaddispatcher::addDelegate。cclayer在自己的成员函数cclayer::setKeypadEnabled中,将自己注册到CCKeypaddispatcher:

@H_898_301@ 19 voID cclayer::setKeypadEnabled( enabled) (enabled!=m_bKeypadEnabled) { m_bKeypadEnabled=enabled; (m_bRunning) CCDirector*pDirector=CCDirector::sharedDirector(); (enabled) pDirector->getKeypaddispatcher()->addDelegate( this ); } else { pDirector->getKeypaddispatcher()->removeDelegate( ); } } } 跟触控处理一样,cclayer默认也不是不开启功能键功能的。

现在我们总结一下怎么在游戏中使用功能键。

方式一:使用自己的Layer。然后重写keyBackClicked和keyMenuClicked函数,并且setKeypadEnabled(true)。

方式二:自己定义了一个处理类,让它继承自CCKeypadDelegate,并实现keyBackClicked和keyMenuClicked函数。然后调用CCDirector::sharedDirector()->getKeypaddispatcher()->addDelegate(pYourOwnHandler)。

AndroID上面,使用的本地方法是Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeKeyDown。有兴趣可以自己研究。

对于字符串的输入是一个比较复杂的话题。Cocos2Dx提供的功能不包括输入法,虽然名字叫做IME。Cocos2Dx提供的处理字符输入的功能包括:从系统接收输入的字符串,然后进行分发;一些常见的输入控件:CCTextFIEldTTF和CCEditBox。Cocos2Dx的GUI部分还是比较弱,很多输入控件的支持都需要自己去做。我们先看下用户输入的流程:

第一步:使得输入控件得到焦点。在手机上一般就会d出虚拟键盘。

第二步:用户输入内容。内容在控件上面得到及时地反应。

第三部:用户输入完毕。可以以回车结束,也可能是通过控件失去焦点。

第一步和第三步是用户 *** 作的主动过程。分别对应到CCIMEDelegate::attachWithIME和CCIMEDelegate::detachWithIME。第二步,每输入一个字或者词, *** 作系统就会将输入的字符通过系统消息的方式告知应用。对应的接口是CCIMEDelegate::insertText和CCIMEDelegate::deleteBackward。

我们先看attachWithIME和detachWithIME。attachWithIME和detachWithIME在CCIMEDelegate中有默认实现。就是调用CCIMEdispatcher::attachDelegateWithIME和CCIMEdispatcher::detachDelegateWithIME。主要功能是在何时的时机调用CCIMEDelegate的四个函数:canAttachWithIME、dIDAttachWithIME、canDetachWithIME和dIDDetachWithIME。带有can前缀的用来测试现在是否可以attach或者detach IME。dID前缀的函数用来通知Delegate现在已经做了attach或detach IME。这些回调函数给Delegate一些处理其它的事务的机会。

但什么怎么触发attachWithIME或者detachWithIME呢?答案是我们自己控制。举一个常见例子:用户点击一个控件。控件在Cocos2Dx可以做成一个cclayer。因为cclayer带有处理触控事件的能力。我们重载cclayer::cctouchend的函数,让它收到控件所在区域的触控消息后,就让 *** 作系统d出键盘允许进行输入,如果触控区域不在控件所在区域,隐藏键盘。

TextFIEldTTFDefaultTest::onClickTrackNode(
bClicked) CCTextFIEldTTF*pTextFIEld=(CCTextFIEldTTF*)m_pTrackNode; (bClicked) { pTextFIEld->attachWithIME(); else pTextFIEld->detachWithIME(); } 这里用到了CCTextFIEldTTF。他是Cocos2Dx提供的一个完整输入控件。虽然还有CCEditBox,但它是以扩展插件的身份存在的,并且实现方式也不一样。CCTextFIEldTTF本身我们后面还会提到。

CCTextFIEldTTF::attachWithIME和CCTextFIEldTTF::detachWithIME内部会先调用CCIMEDelegate::attachWithIME和CCIMEDelegate::detachWithIME。因为CCIMEDelegate::attachWithIME和CCIMEDelegate::detachWithIME会告知控件当前是否允许做IME的attach和detach *** 作。如果CCIMEDelegate的两个函数返回fasle,那么当前控件的IME attach和detach都会被拒绝。

26 CCTextFIEldTTF::attachWithIME()
bRet=CCIMEDelegate::attachWithIME(); (bRet) CCEGLVIEw*pGlVIEw=CCDirector::sharedDirector()->getopenGLVIEw(); (pGlVIEw) { pGlVIEw->setIMEKeyboardState( ); } return bRet; } CCTextFIEldTTF::detachWithIME() bRet=CCIMEDelegate::detachWithIME(); (bRet) { CCEGLVIEw*pGlVIEw=CCDirector::sharedDirector()->getopenGLVIEw(); (pGlVIEw) { ); } bRet; CCTextFIEldTTF::attachWithIME和CCTextFIEldTTF::detachWithIME进一步让 *** 作系统准备输入法。但这步依赖于Cocos2Dx所处的平台,不同的平台有不同的实现,Win32上面上面都不需要做,但AndroID上面就需要自己去通过inputMethodManager获取输入法服务。平台的差异都隐藏在CCEGLVIEw::setIMEKeyboardState后面。有兴趣可以自己进一步深入跟进。

现在再来看CCIMEDelegate::insertText和CCIMEDelegate::deleteBackward。insertText代表我们现在正在进行输入;deleteBackward代表我们现在需要删除一个已经输入的字符。CCIMEDelegate自身并没有对这两个函数提供默认的实现。可用的实现是CCTextFIEldTTF。可用在CCTextFIEldTTF进行自己的扩展。

看到上面的图,可能会问CCIMEDelegate怎么向CCIMEdispatcher进行注册的呢?注释说明了一下:CCIMEDelegate的构造函数会调用CCIMEdispatcher的单例对象的addDelegate函数注册自己。addDelegate是保护成员,为了能够访问它,声明了CCIMEDelegate为CCIMEdispatcher的友元。析构函数会做类似的取消注册 *** 作。CCTextFIEldTTF继承CCIMEDelegate,它构造或析构的时候,会分别调用CCIMEDelegate的构造和析构函数,CCTextFIEldTTF也就自动向CCIMEdispatcher注册和取消注册。

CCTextFIEldTTF的输入字符显示实际上是靠cclabelTTFT完成的。cclabelTTFT还有一个CCTextFIEldDelegate成员,它将一些控制功能封装在一个Delegate当中。CCTextFIEldDelegate所有成员都返回bool值,决定相应的 *** 作是否允许被执行。

现在走一些按键消息的分发流程。CCEGLVIEw::WindowProc在收到键盘消息后,需要进行一下判断:

删除键(VK_BACK),调用CCIMEdispatcher::dispatchDeleteBackward,进一步调用CCIMEDelegate::deleteBackward(子类实现)。

回车键(VK_RETURN),调用CCIMEdispatcher::dispatchInsertText,进一步调用CCIMEDelegate::insertText(子类实现)。但并没有直接送键码,二是送了'\n'。

ASCII字符,同上。

其他可输入字符。在发送前需要做转码,宽字串转UTF8。

CCIMEDelegate的子类CCTextFIEldTTF收到按键输入后,将其存放在一个字符串中。具体的实现,比较易懂,我们就不再累述。

另外,AndroID上面,字符输入相关的代码位于cocos2dx\platform\androID\java\src\org\cocos2dx\lib\Cocos2dxTextinputWraper.java。

总结

以上是内存溢出为你收集整理的Cocos2Dx之处理键盘输入全部内容,希望文章能够帮你解决Cocos2Dx之处理键盘输入所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1045269.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)