呵呵,在游戏或者应用开发中,在高级界面和低级界面之间的切换总是一件让人头疼的事情,高级界面方便,但是难看,低级界面美观,但是一直以来因为在输入法上存在困难(主要是指中文),所以很多产品都是使用了两种界面并存的方式,但我一直想放弃高级界面,采用低级界面来保持产品界面风格的统一,经过N天的努力,终于整成了一套比较好用的输入法,从此可以告别高级界面了,^_^
先讲讲这个输入法的原理,首先程序会从字库文件中将拼音和相应的文字读进内存,其中拼音会放在一个数组里,用来查找,然后字库里的字会以拼音为Key存入一个哈希表,查找的时候,首先根据按键上的字母组合在拼音表里查找是否有适配的拼音,如果有完整适配的拼音则直接从哈希表从取出相应的文字以供选择,下面就给出相应的代码
public class InputMethod implements Const
{
Hashtable hashtable=new Hashtable();
String[] wordKey;
int[] inputKey=new int[10];
int currentPos;
String[] currentInputPad;//当前的输入显示板
public Vector keyAvailable=new Vector(0,1);
Vector wordsBuffer;//上一级的读音的缓存
int select,charSelect;
int screenW,screenH;
int num_row;//每行的字數
int charPage;//頁數
public String inputChar;//輸入的字符
int inputMode;//输入类型 0字母 1数字 2拼音
String[] inputModeTxt={"abc","123","拼音"};
public String content[]={"","",""};//输入的内容,第一维是实际内容,第二维和第三维是用于有光标定位显示的内容
public int charPos;//光标位置
long time1,time2;//按键的时间
int charKeyPos;//字母的切换
String[][] charKey=new String[][]{
{"a","b","c"},
{"d","e","f"},
{"g","h","i"},
{"j","k","l"},
{"m","n","o"},
{"p","q","r","s"},
{"t","u","v"},
{"w","x","y","z"}
};
public InputMethod(int w,int h)
{
screenW=w;
screenH=h;
num_row=(w-10)/20;
charPage=0;
cls();
readWords();
}
/*清空缓存*/
public void cls()
{
currentPos=0;
wordsBuffer=new Vector(0,1);
for(int i=0;i<inputKey.length;i++)
inputKey[i]=-1;
}
/*清空输入内容*/
public void clsContent()
{
content=new String[]{"","",""};
charPos=0;
charSelect=0;
}
public void doUp()
{
if(select>0)
select--;
currentInputPad=null;
}
public void doDown()
{
if(select<keyAvailable.size()-1)
select++;
currentInputPad=null;
}
public void drawInput(Graphics g)
{
try
{
int starty;
if(inputMode==2)
{
if(keyAvailable!=null&&keyAvailable.size()>0)
{
starty=240-keyAvailable.size()*20;
if(keyAvailable.size()>0)
PaintCanvas.drawBox(g, 0, starty, 50,keyAvailable.size()*20, 0xffff00);
g.setColor(0);
for(int i=0;i<keyAvailable.size();i++)
{
if(i==select)
g.setColor(0x00ff00);
else
g.setColor(0x0000ff);
g.fillRect(0,starty+i*18,50,18);
g.setColor(-1);
String key=(String)keyAvailable.elementAt(i);
g.drawString(key,10,starty+i*18,0);
if(i==select)
{
/*查找相应的拼音*/
for(int m=0;m<wordKey.length;m++)
{
/*如果完全适配,就从哈希表里取出相应的字*/
if(key.equals(wordKey[m]))
{
currentInputPad=(String[])hashtable.get(key);
break;
}
}
}
}
}
if(currentInputPad!=null)
{
starty=screenH-65;
drawTextBox(g,0xefefef,0x121212,0x2d3f4d,2,starty,screenW-4,25,2,0);
g.setColor(0xffff00);
for(int i=charPage*num_row;i<(charPage+1)*num_row;i++)
{
System.out.println(i+"."+charPage+"."+num_row+"."+charSelect);
if(i>currentInputPad.length-1)
return;
if(i==charSelect)
{
g.setColor(-1);
g.drawRect(3+(i-charPage*num_row)*20,starty+1,16,20);
}
g.setColor(0xffff00);
g.drawString(currentInputPad[i],5+(i-charPage*num_row)*20,starty+2,0);
}
}
}
PaintCanvas.drawStringShadow(g,-1,0,0,inputModeTxt[inputMode],w,0,24);
}
catch(Exception e)
{
System.out.println("輸入法出錯"+e.toString());
}
}
public void drawTextBox(Graphics g,int color1,int color2,int color3,int stx,int sty,int bw,int bh,int boardW,int type)
{
if(type==0)
{
g.setColor(color1);
g.fillRect(stx-boardW,sty-boardW,bw+2*boardW,bh+2*boardW);
g.setColor(color2);
g.fillRect(stx,sty,bw+boardW,bh+boardW);
g.setColor(color3);
g.fillRect(stx,sty,bw,bh);
}
else
{
g.setColor(color2);
g.fillRect(stx-boardW,sty-boardW,bw+2*boardW,bh+2*boardW);
g.setColor(color1);
g.fillRect(stx,sty,bw+boardW,bh+boardW);
g.setColor(color3);
g.fillRect(stx,sty,bw,bh);
}
}
public void keyPressed(int i)
{
time2=System.currentTimeMillis();
if(i==MIDKEY)
{
if(inputMode==2)
{
if((inputChar=getChar())!=null)
{
cls();
keyAvailable.removeAllElements();
currentInputPad=null;
}
}
}
if(i==SOFTRIGHTKEY)
{
backWord();
// cls();
// keyAvailable=new Vector(0,1);
// currentInputPad=null;
}
if(i>=48&&i<58)
{
if(inputMode==2&&i>=50)
{
if(checkWord(i-50))
{
inputKey[currentPos++]=i-50;
currentInputPad=null;
}
select=0;
}
else if(inputMode==1)
inputChar=""+(i-48);
else if(inputMode==0)
{
if(i>=50)
{
// System.out.println("按键时间"+time2+"."+time1);
if((time2-time1)<500)
{
// System.out.println("连续按键");
charKeyPos++;
if(charKeyPos==charKey[i-50].length)
charKeyPos=0;
// System.out.println("内容长度"+content[0].length()+"光标位置"+charPos);
if(charPos==content[0].length())
{
System.out.println("1");
content[0]=content[0].substring(0,charPos-1);
charPos--;
System.out.println("2");
}
else
content[0]=content[0].substring(0,charPos-1)+content[0].substring(charPos,content[0].length());
refreshContent();
}
inputChar=charKey[i-50][charKeyPos];
}
}
}
if(i==UPKEY)
doUp();
if(i==DOWNKEY)
doDown();
if(i==LEFTKEY)
{
if(charSelect>0)
charSelect--;
if(charSelect%num_row==num_row-1)
charPage--;
}
if(i==RIGHTKEY)
{
if(charSelect<currentInputPad.length-1)
charSelect++;
if(charSelect%num_row==0&&charSelect!=0)
charPage++;
}
/*切换输入法*/
if(i==POUNDKEY)
{
inputMode++;
if(inputMode==inputModeTxt.length)
inputMode=0;
}
/*删除*/
if(i==CKEY)
{
if(charPos>=2&&PaintCanvas.checkFace(content[0].substring(charPos-2,charPos))>-1)
{
content[0]=content[0].substring(0, charPos-2)+content[0].substring(charPos,content[0].length());
charPos-=2;
}
else if(charPos>0)
{
if(charPos==content[0].length())
content[0]=content[0].substring(0,charPos-1);
else
content[0]=content[0].substring(0, charPos-1)+content[0].substring(charPos,content[0].length());
charPos--;
}
refreshContent();
}
time1=time2;
}
/*回退*/
public void backWord()
{
if(wordsBuffer.size()>0)
{
keyAvailable=(Vector)wordsBuffer.elementAt(wordsBuffer.size()-1);
wordsBuffer.removeElementAt(wordsBuffer.size()-1);
currentInputPad=null;
}
}
public void checkWords(Vector temp,String key,int ik)
{
int p;
for(p=0;p<charKey[ik].length;p++)
{
int m;
for(m=0;m<wordKey.length;m++)
{
if(wordKey[m].indexOf(key+charKey[ik][p])==0)
{
temp.addElement(new String(key+charKey[ik][p]));
break;
}
}
}
}
/*检查是否有合适的拼音*/
public boolean checkWord(int ik)
{
Vector temp=new Vector(0,1);
String key="";
if(keyAvailable.size()>0)
{
for(int i=0;i<keyAvailable.size();i++)
{
key=(String)keyAvailable.elementAt(i);
checkWords(temp,key,ik);
}
}
else
checkWords(temp,key,ik);
if(temp.size()>0)
{
wordsBuffer.addElement(keyAvailable);
keyAvailable=temp;
return true;
}
return false;
}
/*从字库里读取文件*/
public void readWords()
{
try
{
InputStream is;
String[] words;
int fontNum=0;
is=getClass().getResourceAsStream("/input/chars.txt");
StringBuffer sb=new StringBuffer();
int c;
int pos=0;
while((c=is.read())!=-1)
{
// System.out.println(c);
if(c=='\n')
{
if(pos==0&&fontNum==0)
{
fontNum=Integer.parseInt(sb.toString());
wordKey=new String[fontNum];
// System.out.println("拼音表长度:"+wordKey.length);
}
else
{
String key;
byte[] data1=new byte[sb.toString().length()];
for(int i=0;i<data1.length;i++)
data1[i]=(byte)sb.charAt(i);
String s=new String(data1,"UTF-8");
key=s.substring(0, s.indexOf("*")).toLowerCase();
// System.out.println(key);
words=new String[s.length()-s.indexOf("*")-1];
for(int j=0;j<words.length;j++)
{
words[j]=s.substring(s.indexOf("*")+1+j,s.indexOf("*")+2+j);
}
hashtable.put(key, words);
wordKey[pos++]=key;
}
sb=new StringBuffer();
}
else if(c!=0x0d)
{
sb.append((char)c);
}
}
String key;
byte[] data1=new byte[sb.toString().length()];
for(int i=0;i<data1.length;i++)
data1[i]=(byte)sb.charAt(i);
String s=new String(data1,"UTF-8");
key=s.substring(0, s.indexOf("*"));
words=new String[s.length()-s.indexOf("*")-1];
for(int j=0;j<words.length;j++)
{
words[j]=s.substring(s.indexOf("*")+1+j,s.indexOf("*")+2+j);
}
hashtable.put(key, words);
wordKey[pos++]=key;
}
catch(Exception e)
{
System.out.println("读取字库出错"+e.toString());
}
}
public String getChar()
{
if(currentInputPad!=null)
return currentInputPad[charSelect];
else
return null;
}
public void setInputMode(int type)
{
inputMode=type;
}
public int getInputMode()
{
return inputMode;
}
public void refreshContent()
{
if(content[0].length()>0)
{
if(charPos==0)
{
content[1]=" "+content[0];
content[2]="|"+content[0];
}
else if(charPos==content[0].length())
{
content[1]=content[0]+" ";
content[2]=content[0]+"|";
}
else
{
content[1]=content[0].substring(0,charPos)+" "+content[0].substring(charPos,content[0].length());
content[2]=content[0].substring(0,charPos)+"|"+content[0].substring(charPos,content[0].length());
}
}
System.out.println(content[0]);
System.out.println(content[1]);
System.out.println(content[2]);
}
/*移动光标*/
public void moveCharPos(int direct)
{
if(direct==0)
{
if(charPos>2)
{
System.out.println(content[0].substring(charPos-2,charPos));
if(PaintCanvas.checkFace(content[0].substring(charPos-2,charPos))>-1)
charPos-=2;
else
charPos--;
}
else if(charPos>0)
charPos--;
}
else
{
if(charPos<content[0].length()-2)
{
if(PaintCanvas.checkFace(content[0].substring(charPos+1,charPos+3))>-1)
charPos+=2;
else
charPos++;
}
else if(charPos<content[0].length())
charPos++;
}
refreshContent();
}
}
这个代码实现了用#号键切换英文,数字,拼音之间的输入法切换(不好意思,暂时没有加入标点输入),然后在自己的Canvas界面中通过如下按键控制
/*输入法的按键*/
public void keyPressedInput(int i)
{
if(!chooseFace&&down&&imt.keyAvailable.size()==0)
{
chooseFace=true;
faceNo=7;
}
else if(!chooseFace&&left&&imt.keyAvailable.size()==0)
{
imt.moveCharPos(0);
}
else if(!chooseFace&&right&&imt.keyAvailable.size()==0)
{
imt.moveCharPos(1);
}
else if(chooseFace)
{
if(left)
{
if(faceNo==0)
faceNo=face.rows*face.columns-1;
else
faceNo--;
}
else if(right)
{
if(faceNo==face.rows*face.columns-1)
faceNo=0;
else
faceNo++;
}
else if(up)
chooseFace=false;
else if(fire||softLeft)
{
imt.content[0]+=faceSign[faceNo];
imt.charPos+=2;
imt.refreshContent();
}
}
else if(softRight)
{
if(imt.keyAvailable==null||imt.keyAvailable.size()==0)
{
drawMessage=-1;
imt.clsContent();
}
else
imt.keyPressed(-7);
}
else if(softLeft)
{
if(imt.keyAvailable.size()==0)
{
if(imt.content[0]!=null&&imt.content[0].length()>0)
{
sendMessage(drawMessage);
}
else
setNotice("对不起,你输入的信息为空");
drawMessage=-1;
}
}
else
{
imt.keyPressed(i);
if(imt.inputChar!=null)
{
if(imt.content[0]==null||imt.content[0].length()==0)
imt.content[0]=imt.inputChar;
else
imt.content[0]=imt.content[0].substring(0,imt.charPos)+imt.inputChar+imt.content[0].substring(imt.charPos, imt.content[0].length());
imt.inputChar=null;
imt.charPos++;
}
}
imt.refreshContent();
}
这里面有一些我自己的工程中要用到的类,大家看的时候注意区分一下,呵呵,比如chooseFace是为了我们这边需要插入表情头像用的,大家可以不用,绘制的时候,交替显示inputmethod里的content[1]和content[2],确定需要用到输入内容的时候,调用inputmethod里的content[0]就行了。
另外给一下字库文件的格式
392
A*啊阿腌
Ai*爱矮挨哎碍癌艾唉哀蔼隘埃皑呆嫒暧捱
字库文件是一个TXT文件,第一行的数字标明这个字库里有多少拼音,然后每一行是拼音和字库,这个文件可以自己随意定义。
OK,就说这么多吧,大家有看不明白的地方,可以找我交流一下,谢谢。
你可以使用这个链接引用该篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=6277574
|
- 评论人:广州|C
2008-08-04 09:37:10
|
|||
想问一下,用手机自带的输入法不能用吗?还要自己写一个? |
||||
|
- 评论人:anouymous
2007-05-18 17:41:40
|
|||
内嵌组件是什么东西? |
||||
|
- 评论人:刀刀
2007-05-17 15:40:15
|
|||
回答一下,内嵌组件的界面很不好看,不符合游戏的风格,至于字库,目前4000来字是14K |
||||
|
- 评论人:anonymous
2007-05-16 19:10:14
|
|||
什么编码-8?
|
||||
|
- 评论人:anonymous
2007-05-16 16:51:17
|
|||
为什么不用内嵌组件呐 |
||||