- 浏览: 16859 次
- 性别:
- 来自: 北京
最新评论
Panda3D支持微软输入法的DirectEntry控件
昨天在博客里提到了Panda3D对于中文输入的问题,没有收到什么解答。昨晚从8点到凌晨4点,除去中间零零碎碎的其他事情,大约花了5、6个小时的时间搞了一个简单的解决方法。在这里记录一下整个思考过程,并把自己实现的控件源码提供出来,希望有人可以给出更加优美完善的解决方案。 首先,说明一下Panda3D输入中文时存在的问题,使用DirectEntry控件,切换到搜狗等输入法尝试输入,会发现没有什么效果,而且再切换回英文键盘也无法继续输入,只能响应删除字符等控制操作。 Mentor说了,在游戏中,一般实现中文输入有两种方法,第一是使用操作系统的输入法,第二是自己实现一套输入法。以我现在做Mini项目的进度,第二个明显hold不住,于是只能尝试使用第一种方法。我在DirectEntry中切换到微软输入法,惊奇地发现可以输入字符,但是显示的结果是乱码。 如果可以输入,那么显示的乱码和输入的中文肯定有一点的关系!基于这一思考,我输入“中文”,然后用repr()将DirectEntry中的内容在控制台打印出来,结果是:u'\xd6\xd0\xce\xc4',这明显不是utf-8格式的字符,出于好奇,我拿这个去google搜索了一下,发现'\xd6\xd0\xce\xc4'是“中文”的gb2312格式编码,这就可以解释为什么会显示为乱码的原因,'\xd6\xd0\xce\xc4'应该是一个长度为2个宽字符的字串,而u'\xd6\xd0\xce\xc4'的长度为4,Panda3D将输入法的输入识别为unicode,但是没有做相应的合并。我不清楚这是我的设置问题还是Panda3D的一个bug,问题的根源找到了,那么就可以想办法解决了。只需要将u'\xd6\xd0\xce\xc4'变为s='\xd6\xd0\xce\xc4',然后使用s.decode('gb2312')就可以转化为可供显示的中文了。 想要解决这个问题,需要查阅DirectEntry底层的实现,而DirectEntry.py提供给的信息太少了,我猜测底层的键盘响应应该是用C++封装的,只给python提供了一些接口,那么从根源拦截字符输入就比较困难。另外一种折中方案是在输入之后显示之前修改内容,这样就需要能够监听按键输入的事件。在分析DirectEntry之后,找到了如下的方法: 第一个是Type事件,第二个是控件的输入超出长度的事件,第三个是擦除事件。经过测试发现,后面三个函数调用的时间都是在底层已经更改完self.guiItem的内容之后才会触发的,也就是说完全截获输入去修改的想法不太容易实现。在我将事件响应函数的参数guiEvent打印出来之后发现,每次输入一个字符就会调用一个_handleType函数,并且guiEvent.getKeycode()为对应输入的字符。 对于英文字符和符号,ascii码的范围是0~127,大于等于128的我可以判定为unicode的一半。基于这一假设,我自己维护一个输入内容self.showingContent,然后对于小于128的字符直接处理,对于大于127的字符首先存放到self.tempchar中,累积为2个的时候,取出来合并为一个gb2312编码的unicode字符,刷新输入内容即可。 最后的结果就是以继承自DirectEntry的方式实现,因为时间关系,一些初始化代码直接从父类拷贝过来,没有精简,具体代码如下,考虑了光标的移动等内容处理,还有长度溢出半个字符的情况等。 时间关系,实现得较为简陋。而且经过我自己的测试,在微软输入法下,按Shift键切换中英文输入,也会导致输入框无法再响应输入的问题,我猜测这和搜狗输入法一样,对于Panda3D底层的按键响应事件产生了影响。上一张实现结果。。。 上述的思考过程和实现结果仅供参考,如果有人可以提供更好的办法或者在此基础上的改进,烦劳知会,谢谢~ E-mail:jiaweihao1987@gmail.com 源码见附件。 self.accept(self.guiItem.getTypeEvent(), self._handleTpye)
self.accept(self.guiItem.getOverflowEvent(), self._handleOverFlow)
self.accept(self.guiItem.getEraseEvent(), self._handleEease)
# -*- coding: utf-8 -*-
# Author: Daivd
# Date : 2012-09-02
# E-Mail: jiaweihao1987@gmail.com
# If you have any questions or better solution, let me know.
# Thanks.
# State: This class is not the perfect solution for Chinese input in Panda3D.
# You have to use Microsoft Pinyin or Smart ABC as IME.
# You'd better not use the Shift key to switch Chinese input to English input,
# which may make the type listener out of operation.
# Panda3D is Open Source and free for any purpose, so is this file.
# Enjoy it!
__all__ = ['ChiDirectEntry']
from direct.gui.DirectGui import DirectEntry
from pandac.PandaModules import *
import direct.gui.DirectGuiGlobals as DGG
from direct.gui.DirectFrame import *
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
# ChiDirectEntry States:
ENTRY_FOCUS_STATE = PGEntry.SFocus # 0
ENTRY_NO_FOCUS_STATE = PGEntry.SNoFocus # 1
ENTRY_INACTIVE_STATE = PGEntry.SInactive # 2
class ChiDirectEntry(DirectEntry):
"""
ChiDirectEntry(parent) - Create a DirectGuiWidget which responds
to keyboard buttons
"""
directWtext = ConfigVariableBool('direct-wtext', 1)
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
# A Direct Frame can have:
# - A background texture (pass in path to image, or Texture Card)
# - A midground geometry item (pass in geometry)
# - A foreground text Node (pass in text string or Onscreen Text)
# For a direct entry:
# Each button has 3 states (focus, noFocus, disabled)
# The same image/geom/text can be used for all three states or each
# state can have a different text/geom/image
# State transitions happen automatically based upon mouse interaction
optiondefs = (
# Define type of DirectGuiWidget
('pgFunc', PGEntry, None),
('numStates', 3, None),
('state', DGG.NORMAL, None),
('entryFont', None, DGG.INITOPT),
('width', 10, self.setup),
('numLines', 1, self.setup),
('focus', 0, self.setFocus),
('cursorKeys', 1, self.setCursorKeysActive),
('obscured', 0, self.setObscureMode),
# Setting backgroundFocus allows the entry box to get keyboard
# events that are not handled by other things (i.e. events that
# fall through to the background):
('backgroundFocus', 0, self.setBackgroundFocus),
# Text used for the PGEntry text node
# NOTE: This overrides the DirectFrame text option
('initialText', '', DGG.INITOPT),
# Command to be called on hitting Enter
('command', None, None),
('extraArgs', [], None),
# Command to be called when enter is hit but we fail to submit
('failedCommand', None, None),
('failedExtraArgs',[], None),
# commands to be called when focus is gained or lost
('focusInCommand', None, None),
('focusInExtraArgs', [], None),
('focusOutCommand', None, None),
('focusOutExtraArgs', [], None),
# Sounds to be used for button events
('rolloverSound', DGG.getDefaultRolloverSound(), self.setRolloverSound),
('clickSound', DGG.getDefaultClickSound(), self.setClickSound),
('autoCapitalize', 0, self.autoCapitalizeFunc),
('autoCapitalizeAllowPrefixes', ChiDirectEntry.AllowCapNamePrefixes, None),
('autoCapitalizeForcePrefixes', ChiDirectEntry.ForceCapNamePrefixes, None),
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
# Initialize superclasses
DirectEntry.__init__(self, parent)
if self['entryFont'] == None:
font = DGG.getDefaultFont()
else:
font = self['entryFont']
# Create Text Node Component
self.onscreenText = self.createcomponent(
'text', (), None,
OnscreenText,
(), parent = hidden,
# Pass in empty text to avoid extra work, since its really
# The PGEntry which will use the TextNode to generate geometry
text = '',
align = TextNode.ALeft,
font = font,
scale = 1,
# Don't get rid of the text node
mayChange = 1)
# We can get rid of the node path since we're just using the
# onscreenText as an easy way to access a text node as a
# component
self.onscreenText.removeNode()
# Bind command function
self.bind(DGG.ACCEPT, self.commandFunc)
self.bind(DGG.ACCEPTFAILED, self.failedCommandFunc)
self.accept(self.guiItem.getFocusInEvent(), self.focusInCommandFunc)
self.accept(self.guiItem.getFocusOutEvent(), self.focusOutCommandFunc)
# listen for auto-capitalize events on a separate object to prevent
# clashing with other parts of the system
self._autoCapListener = DirectObject()
# Call option initialization functions
self.initialiseoptions(ChiDirectEntry)
if not hasattr(self, 'autoCapitalizeAllowPrefixes'):
self.autoCapitalizeAllowPrefixes = ChiDirectEntry.AllowCapNamePrefixes
if not hasattr(self, 'autoCapitalizeForcePrefixes'):
self.autoCapitalizeForcePrefixes = ChiDirectEntry.ForceCapNamePrefixes
# Update TextNodes for each state
for i in range(self['numStates']):
self.guiItem.setTextDef(i, self.onscreenText.textNode)
# Now we should call setup() again to make sure it has the
# right font def.
self.setup()
# Update initial text
self.unicodeText = 0
if self['initialText']:
self.enterText(self['initialText'])
self.accept(self.guiItem.getTypeEvent(), self._handleTpye)
self.accept(self.guiItem.getOverflowEvent(), self._handleOverFlow)
self.accept(self.guiItem.getEraseEvent(), self._handleEease)
if self['initialText']:
self.showingContent = unicode(self['initialText'], 'utf-8')
else:
self.showingContent = u''
self.tempchar = None
def _handleOverFlow(self, guiEvent):
self.tempchar = None
def _handleTpye(self, guiEvent):
pos = self.guiItem.getCursorPosition()
addition = ''
if guiEvent.getKeycode() <= 0:
self.tempchar = None
return
if guiEvent.getKeycode() < 128:
addition = unichr(guiEvent.getKeycode())
elif self.tempchar == None:
self.tempchar = guiEvent.getKeycode()
else:
s = '\\x%x\\x%x'%(self.tempchar, guiEvent.getKeycode())
tempC = ''
try :
exec("tempC = unicode('%s', 'gb2312')"%s)
except:
pass
addition = tempC
self.tempchar = None
if len(self.get()) != len(self.showingContent):
diff = len(self.get()) - len(self.showingContent)
pos -= diff
if addition != '':
self.showingContent = self.showingContent[:pos] + addition + self.showingContent[pos:]
pos += 1
self.setCursorPosition(pos)
self.set(self.showingContent)
def _handleEease(self, guiEvent):
self.tempchar = None
pos = self.guiItem.getCursorPosition()
self.showingContent = self.showingContent[:pos] + self.showingContent[pos+1:]
def set(self, text):
self.showingContent = text
DirectEntry.set(self, self.showingContent)
def get(self):
return DirectEntry.get(self)
- ChiDirectEntry.rar (3.2 KB)
- 下载次数: 2
相关推荐
用Panda3D开发3D枪战类游戏源码,脚本可以直接运行。 功能包括:开始动画、穿戴商店、关卡设计、场景切换、运动控制、对战特效。包括音效、地图实现,包括实现HUD模块。
panda3d 引擎使用例子 panda3d-1.10.13\samples\asteroids panda3d-1.10.13\samples\ball-in-maze panda3d-1.10.13\samples\boxing-robots panda3d-1.10.13\samples\bump-mapping panda3d-1.10.13\samples\carousel ...
Panda3D是一个免费的开源游戏引擎。它已经被爱好者和大型工作室成功地用于创建游戏,从快速原型到大规模的商业mmo。Panda3D使得使用模型、纹理和声音很容易创造令人印象深刻的交互体验。通过这本书,你也将能够充分...
python panda3d 实例
python项目开发实战_大型3D枪战类冒险游戏(Panda3D)_编程案例实例课程教程.pdf
Panda3D 1.7 Game Developers Cookbook . Source Code Panda3D是一个免费的开源游戏引擎。它已经被业余爱好者和大型工作室成功地用于创建从快速原型到全面商业mmo的各种游戏。Panda3D使模型、纹理和声音易于使用,...
panda3d详细的开发手册,从官方网页下载
Panda3D还支持C++和其他编程语言。它使用先进的渲染技术,包括阴影、光照和反射,可以创建令人惊叹的视觉效果。它还提供了丰富的工具和资源,使开发者能够快速创建和部署游戏。Panda3D被广泛用于游戏开发、虚拟现实...
Panda3d 1.6 Game Engine
使用panda3d游戏引擎,用C++的语言,添加贴图,动态添加棋子模型,实现五子棋的基本方法。
Panda3D 1.7 Game Developer's Cookbook 英文无水印pdf pdf使用FoxitReader和PDF-XChangeViewer测试可以打开
Packt.Panda3D.1.7.Game.Developer's.Cookbook.2011
Panda3D - 一个游戏引擎,一个3D渲染框架和Python与C 程序游戏开发
Panda3D引擎的经典教程。本书为英文版,供游戏开发者参考,学习。
这应该避免任何导出/导入问题,因为模型是从Panda3D Studio中以.bam文件导出的,.bam文件的数据紧密反映了用于渲染的实际Panda3D结构。 还支持导出到.obj文件,这将吸引那些对创建模型以导入到支持此文件类型的...
python库,解压后可用。 资源全名:panda3d_tmx2bam-0.0.251-py3-none-any.whl
Packt.Panda3D.1.6.Game.Engine.Beginners.Guide
资源分类:Python库 所属语言:Python 资源全名:panda3d-1.10.8-cp38-cp38-manylinux1_x86_64.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
Panda3D是一个游戏引擎,是用于Python和C ++程序的3D渲染和游戏开发的框架。 由于Panda3D具有,因此它是开源的,并且对于任何目的(包括商业活动)都是免费的。 要了解有关Panda3D功能的更多信息,请访问和。 要...