在软键盘上绘制焦点并移动焦点

来源:互联网 发布:网络攻击方式 编辑:程序博客网 时间:2024/05/30 23:01

原文地址:http://www.eoeandroid.com/blog-126933-105.html

TV上的软键盘不需要再在TVtouch软键盘按钮,需要通过遥控器进行操作,因此需要在软键盘上知道目前是在哪个键子上,这需要通过焦点来实现。

LatinIME输入法改写功能代码:

添加功能:为输入法软键盘键子添加焦点(边框),并支持键盘上的方向键,在按上下左右方向键时,焦点跟着方向键移动;并支持键盘回车按钮,在按下回车键后,将软键盘对应键子内容输入到editor(编辑框);

代码修改描述:

要拦截键盘的按钮事件,需要在代码中重写onKeyDown(int keyCode, KeyEvent event)方法,参数keyCode可以是键盘上按键对应的KeyEevent中的值。要使有效输入法拦截键盘上按键事件,需要在特定类中重写onKeyDown(int keyCode, KeyEvent event)方法。一开始我重写的是LatinKeyboardView中的onKeyDown(int keyCode, KeyEvent event)方法,但在运行后,没有拦截到键盘上的方向键按钮的down事件,后经过查询相关的知识点,知道了输入法的执行入口是InputMethodService类及其子类,在其中有创建输入法软键盘的一系列回调方法,用以创建输入视图,候选区视图等。要拦截键盘的按钮事件,也需要在InputMethodService子类中重写onKeyDown(int keyCode, KeyEvent event)方法,然后运行到模拟器上,你在按下键盘上的方向键时,输入法就可以有效拦截你的键盘按钮事件,我在LatinIME中的onKeyDown(int keyCode, KeyEvent event)方法中的添加方向键按钮事件,通过控制键子在键盘上的xy来控制焦点的移动;

焦点的移动:

在软件盘上画焦点,并跟随键盘方向键进行移动。

首先要做的是在适当的类中,画出焦点,实际上的焦点是通过在键子边上画边框来实现,android中可以通过重写onDraw(Canvas canvas)方法来实现;要在软键盘的输入视图上的键子上画边框,就不是在LatinIME这个InputMethodService子类中重写onDraw(Canvas canvas)方法了,而应该是在创建输入视图的类中进行重写onDraw(Canvas canvas)方法,及在LatinKeyboardView类(KeyboardView的子类)中重写onDraw(Canvas canvas)

代码实现:

LatinKeyboardView中重写onDraw(Canvas canvas),在键子边上画边框,所有添加的代码如下:

/** draw focus on the visual keyboard (motified,override onDraw() Method Self)****/

private KeyboardcurrentKeyboard;

private List<Key>keys =new ArrayList<Key>();

privateintlastKeyIndex = 0;

private KeyfocusedKey;

private Rectrect;

/**

* modified onDraw method(Overriding)

*/

@Override

publicvoid onDraw(Canvas canvas) {

super.onDraw(canvas);

currentKeyboard = this.getKeyboard();

keys = currentKeyboard.getKeys();

Paint p = new Paint();

p.setColor(Color.CYAN);

p.setStyle(Style.STROKE);

p.setStrokeWidth(3.75f);

focusedKey = keys.get(lastKeyIndex);

rect = new Rect(

focusedKey.x,focusedKey.y + 4,

focusedKey.x +focusedKey.width,

focusedKey.y +focusedKey.height

);

canvas.drawRect(rect, p);

}

/** provide lastKeyIndex access */

publicint getLastKeyIndex() {

returnlastKeyIndex;

}

/** set key index */

publicvoid setLastKeyIndex(int index) {

this.lastKeyIndex = index;

}

/**** draw focus on the visual keyboard (motified) ********/

在运行后的效果图片已上传

下来要实现的是在按下上下左右方向键时,焦点跟随发想见移动,与之前说的一样,在LatinIME类中重写onKeyDown(int keyCode, KeyEvent event),在方法中对方向键进行判断,并设计焦点移动移动过程。代码段如下:

/**************fields to use for current keyboard displaying *************/

privateintnCurKeyboardKeyNums;

private KeyboardnCurrentKeyboard;

private List<Keyboard.Key>nKeys;

privateintnLastKeyIndex = 0;

privatevoid setFields() {

if (null ==mInputView)return;

nCurrentKeyboard = mInputView.getKeyboard();

nKeys = nCurrentKeyboard.getKeys();

nCurKeyboardKeyNums =nKeys.size();

nLastKeyIndex = mInputView.getLastKeyIndex();

}

@Override

publicboolean onKeyDown(int keyCode, KeyEvent event) {

switch (keyCode) {

case KeyEvent.KEYCODE_BACK:

if (event.getRepeatCount() == 0 &&mInputView !=null) {

if (mInputView.handleBack()) {

returntrue;

} elseif (mTutorial !=null) {

mTutorial.close();

mTutorial = null;

}

}

break;

// down direction

case KeyEvent.KEYCODE_DPAD_DOWN:

// If tutorial is visible, don't allow dpad to work

if (mTutorial !=null) {

returntrue;

}

setFields();

if (nLastKeyIndex >=nCurKeyboardKeyNums - 1) {

if (null ==mInputView)returnfalse;

mInputView.setLastKeyIndex(0);

} else {

int[] nearestKeyIndices =nCurrentKeyboard.getNearestKeys(

nKeys.get(nLastKeyIndex).x,nKeys.get(nLastKeyIndex).y);

for (int index : nearestKeyIndices) {

if (nLastKeyIndex < index) {

Key nearKey = nKeys.get(index);

Key lastKey = nKeys.get(nLastKeyIndex);

if (

((lastKey.x >= nearKey.x)// left side compare

&& (lastKey.x < (nearKey.x + nearKey.width)))

|| (((lastKey.x + lastKey.width) > nearKey.x)// right side compare

&& ((lastKey.x + lastKey.width) <= (nearKey.x + nearKey.width)))

)

{

mInputView.setLastKeyIndex(index);

break;

}

}

}// end for loop

}

mInputView.invalidate();

returntrue;

// up direction

case KeyEvent.KEYCODE_DPAD_UP:

// If tutorial is visible, don't allow dpad to work

if (mTutorial !=null) {

returntrue;

}

setFields();

if (nLastKeyIndex <= 0) {

if (null ==mInputView)returnfalse;

mInputView.setLastKeyIndex(nCurKeyboardKeyNums - 1);

} else {

int[] nearestKeyIndices =nCurrentKeyboard.getNearestKeys(

nKeys.get(nLastKeyIndex).x,nKeys.get(nLastKeyIndex).y);

for (int i = nearestKeyIndices.length - 1; i >= 0; i--) {

int index = nearestKeyIndices[i];

if (nLastKeyIndex > index) {

Key nearKey = nKeys.get(index);// get the next key

Key nextNearKey = nKeys.get(index + 1);

Key lastKey = nKeys.get(nLastKeyIndex);// get current displayed

if (

((lastKey.x >= nearKey.x) &&

(lastKey.x < (nearKey.x + nearKey.width)) &&

(((lastKey.x + lastKey.width) <= (nextNearKey.x + nextNearKey.width))

|| ((lastKey.x + lastKey.width) > nextNearKey.x)))

)

{

mInputView.setLastKeyIndex(index);

break;

}

}

}// end for loop

}

mInputView.invalidate();

returntrue;

// left direction

case KeyEvent.KEYCODE_DPAD_LEFT:

// If tutorial is visible, don't allow dpad to work

if (mTutorial !=null) {

returntrue;

}

setFields();

if (nLastKeyIndex <= 0) {

if (null ==mInputView)returnfalse;

mInputView.setLastKeyIndex(nCurKeyboardKeyNums - 1);

} else {

nLastKeyIndex--;

mInputView.setLastKeyIndex(nLastKeyIndex);

}

mInputView.invalidate();

//break;

returntrue;

// right direction

case KeyEvent.KEYCODE_DPAD_RIGHT:

// If tutorial is visible, don't allow dpad to work

if (mTutorial !=null) {

returntrue;

}

setFields();

if (nLastKeyIndex >=nCurKeyboardKeyNums - 1) {

if (null ==mInputView)returnfalse;

mInputView.setLastKeyIndex(0);

} else {

nLastKeyIndex++;

mInputView.setLastKeyIndex(nLastKeyIndex);

}

mInputView.invalidate();

returntrue;

// Enter key

case KeyEvent.KEYCODE_ENTER:

if (mTutorial !=null) {

returntrue;

}

if (null ==mInputView)returnfalse;

setFields();

int curKeyCode =nKeys.get(nLastKeyIndex).codes[0];

switch (curKeyCode) {

case Keyboard.KEYCODE_MODE_CHANGE:

case Keyboard.KEYCODE_CANCEL:

case Keyboard.KEYCODE_DELETE:

case Keyboard.KEYCODE_SHIFT:

case LatinKeyboardView.KEYCODE_OPTIONS:

case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE:

case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:

case LatinKeyboardView.KEYCODE_SHIFT_LONGPRESS:

case LatinKeyboardView.KEYCODE_VOICE:

onKey(curKeyCode, null);

returntrue;

case 9/*Tab*/:

onKey(9, null);

default:

if (mKeyboardSwitcher.isAlphabetMode() &&mInputView.isShifted()) {

getCurrentInputConnection().commitText(String.valueOf((char) curKeyCode).toUpperCase(), 1);

} else {

getCurrentInputConnection().commitText(String.valueOf((char) curKeyCode), 1);

}

returntrue;

}

}

returnsuper.onKeyDown(keyCode, event);

}

代码实现了对键盘上上下左右方向键的事件拦截,并使软键盘上焦点跟随移动。实现截图已上传。

主要注意的是

由于android系统自带的LatinIME输入法是第三方插件式输入法,其自身无法被作为一个android工程被单独导出创建,必须依赖于整个系统源码环境。因此,要修改LatinIME输入法,必须在源码大环境下进行修改,编译,再进行测试。

开发环境:ubuntu+eclipse+adt

ubuntueclipse之下导入整个android系统源码,当然是在编译成功的源码,导入源码时需要做的时创建java project而非android project,然后基于以后的源码进行创建工程,需要进行修改的输入法在路径:工程名>packages>inputmethods>输入法包,在其中找到需要进行修改的java文件,进行修改即可。

在修改了一点代码后,向进行测试,需要经过部分编译,在进入到具体的输入法根目录下,在终端中输入mm命令即可,(如果提示需要安装什么软件,那是因为在刚进入到android系统源码根目录下,需要先只是shell文件。即先进入到android系统源码根目录下,执行 . build/envsetup.sh 命令,这样就会多出一些命令,具体多出的命令可以在网上找到不少资源,就不再说了,这边最常用的就是mm这个进行局部编译的命令。在修改并且编译完成后,由于生成apk文件,而原有的系统中已有改应用,需要进行重新安装,执行命令 adb install –r apk文件的完整路径)。

在上面的添加过程中,会有一些小的bug,可以自己尝试修改,主要是判断mInputView(即LatinKeyboardView对象是否为空,是否在屏幕上显示及是否Shifted)。

在测试的时候会发现,如果一个页面(Activity)有两个或以上编辑框,且都指定了键盘类型(在XML文件内配置配置了android:imeOptions属性),那么在输入法软键盘上按回车按钮,内容输入了,但是随之编辑框焦点也发生移动,跳至另一个编辑框。原因在于android输入系统的运行机理,在按钮事件传递路径有关。

绘制焦点效果

焦点移动

 

 

连接学习:http://www.oschina.net/question/116252_15138

 
链接代码:http://download.csdn.net/detail/snowgeneral/3227213#comment
原创粉丝点击