fixed #490 Text input on android use a different way, TextInputTest OK now.

This commit is contained in:
yangws 2011-05-30 16:36:12 +08:00
parent a5c9b8631c
commit 7e2d1d5c48
14 changed files with 330 additions and 229 deletions

View File

@ -2,99 +2,93 @@ package org.cocos2dx.lib;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Build.VERSION;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
class Cocos2dxInputConnection extends BaseInputConnection {
private static final boolean mDebug = false;
void LogD(String msg) {
if (mDebug) {
Log.d("Cocos2dxInputConnection", msg);
}
class TextInputWraper implements TextWatcher, OnEditorActionListener {
private static final Boolean debug = false;
private void LogD(String msg) {
if (debug) Log.d("TextInputFilter", msg);
}
private Cocos2dxGLSurfaceView mView;
private String mLastCommit;
Cocos2dxInputConnection(Cocos2dxGLSurfaceView view) {
super(view, false);
mView = view;
mLastCommit = "";
LogD("SDK Version(" + VERSION.SDK_INT + "):\n "
+ "Release: " + VERSION.RELEASE + "\n "
+ "Incremental: " + VERSION.INCREMENTAL + "\n "
+ "CodeName: " + VERSION.CODENAME);
}
private Cocos2dxGLSurfaceView mMainView;
private String mText;
private String mOriginText;
private Boolean isFullScreenEdit() {
InputMethodManager imm = (InputMethodManager)mMainView.getTextField().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.isFullscreenMode();
}
public TextInputWraper(Cocos2dxGLSurfaceView view) {
mMainView = view;
}
public void setOriginText(String text) {
mOriginText = text;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
super.commitText(text, newCursorPosition);
if (null != mView) {
final String insertText = text.toString();
mLastCommit = insertText;
mView.insertText(insertText);
LogD("commitText: " + insertText);
public void afterTextChanged(Editable s) {
if (isFullScreenEdit()) {
return;
}
return true;
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request,
int flags) {
LogD("getExtractedText: " + request.toString() + "," + flags);
return new ExtractedText();
}
@Override
public boolean performEditorAction(int editorAction) {
LogD("performEditorAction: " + editorAction);
if (null != mView) {
final String insertText = "\n";
mLastCommit = insertText;
mView.insertText(insertText);
LogD("afterTextChanged: " + s);
int nModified = s.length() - mText.length();
if (nModified > 0) {
final String insertText = s.subSequence(mText.length(), s.length()).toString();
mMainView.insertText(insertText);
LogD("insertText(" + insertText + ")");
}
return true;
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
LogD("sendKeyEvent: " + event.toString());
super.sendKeyEvent(event);
if (null != mView) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DEL:
if (KeyEvent.ACTION_UP == event.getAction()) {
mView.deleteBackward();
}
break;
else {
for (; nModified < 0; ++nModified) {
mMainView.deleteBackward();
LogD("deleteBackward");
}
}
return true;
mText = s.toString();
}
@Override
public boolean finishComposingText() {
LogD("finishComposingText");
mLastCommit = "";
return super.finishComposingText();
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
LogD("beforeTextChanged(" + s + ")start: " + start + ",count: " + count + ",after: " + after);
mText = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public CharSequence getTextBeforeCursor(int n, int flags) {
LogD("getTextBeforeCursor");
return mLastCommit;
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (mMainView.getTextField() == v && isFullScreenEdit()) {
// user press the action button, delete all old text and insert new text
for (int i = mOriginText.length(); i > 0; --i) {
mMainView.deleteBackward();
LogD("deleteBackward");
}
String text = v.getText().toString();
if ('\n' != text.charAt(text.length() - 1)) {
text += '\n';
}
final String insertText = text;
mMainView.insertText(insertText);
LogD("insertText(" + insertText + ")");
}
return false;
}
}
@ -104,8 +98,9 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
private static final String TAG = Cocos2dxGLSurfaceView.class.getCanonicalName();
private Cocos2dxRenderer mRenderer;
private final boolean debug = false;
private static final boolean debug = false;
///////////////////////////////////////////////////////////////////////////
// for initialize
///////////////////////////////////////////////////////////////////////////
@ -123,6 +118,38 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
mRenderer = new Cocos2dxRenderer();
setFocusableInTouchMode(true);
setRenderer(mRenderer);
textInputWraper = new TextInputWraper(this);
handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case HANDLER_OPEN_IME_KEYBOARD:
if (null != mTextField && mTextField.requestFocus()) {
mTextField.removeTextChangedListener(textInputWraper);
mTextField.setText("");
String text = (String)msg.obj;
mTextField.append(text);
textInputWraper.setOriginText(text);
mTextField.addTextChangedListener(textInputWraper);
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mTextField, 0);
Log.d("GLSurfaceView", "showSoftInput");
}
break;
case HANDLER_CLOSE_IME_KEYBOARD:
if (null != mTextField) {
mTextField.removeTextChangedListener(textInputWraper);
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mTextField.getWindowToken(), 0);
Log.d("GLSurfaceView", "HideSoftInput");
}
break;
}
}
};
mainView = this;
}
@ -151,46 +178,44 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
///////////////////////////////////////////////////////////////////////////
// for text input
///////////////////////////////////////////////////////////////////////////
private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
private static Handler handler;
private static TextInputWraper textInputWraper;
private TextView mTextField;
public TextView getTextField() {
return mTextField;
}
public void setTextField(TextView view) {
mTextField = view;
if (null != mTextField && null != textInputWraper) {
LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mTextField.getLayoutParams();
linearParams.height = 0;
mTextField.setLayoutParams(linearParams);
mTextField.setOnEditorActionListener(textInputWraper);
}
}
public static void openIMEKeyboard() {
if (null == mainView) {
return;
}
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
imm.showSoftInput(mainView, 0);
}
public static void closeIMEKeyboard() {
if (null == mainView) {
return;
}
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
imm.hideSoftInputFromWindow(mainView.getWindowToken(), 0);
}
private Cocos2dxInputConnection ic;
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT;
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
outAttrs.initialSelStart = -1;
outAttrs.initialSelEnd = -1;
outAttrs.initialCapsMode = 1;
if (null == ic)
{
ic = new Cocos2dxInputConnection(this);
}
Message msg = new Message();
msg.what = HANDLER_OPEN_IME_KEYBOARD;
msg.obj = mainView.getContentText();
handler.sendMessage(msg);
return ic;
}
private String getContentText() {
return mRenderer.getContentText();
}
public static void closeIMEKeyboard() {
Message msg = new Message();
msg.what = HANDLER_CLOSE_IME_KEYBOARD;
handler.sendMessage(msg);
}
public void insertText(final String text) {
queueEvent(new Runnable() {
@Override

View File

@ -96,7 +96,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
public void handleDeleteBackward() {
nativeDeleteBackward();
}
public String getContentText() {
return nativeGetContentText();
}
private static native void nativeInsertText(String text);
private static native void nativeDeleteBackward();
private static native String nativeGetContentText();
}

View File

@ -110,7 +110,7 @@ void CCNode::arrayMakeObjectsPerformSelector(CCArray* pArray, callbackFunc func)
CCARRAY_FOREACH(pArray, child)
{
CCNode* pNode = (CCNode*) child;
if(pNode && (NULL != func))
if(pNode && func)
{
(pNode->*func)();
}
@ -919,7 +919,7 @@ void CCNode::schedule(SEL_SCHEDULE selector)
void CCNode::schedule(SEL_SCHEDULE selector, ccTime interval)
{
CCAssert( selector != NULL, "Argument must be non-nil");
CCAssert( selector, "Argument must be non-nil");
CCAssert( interval >=0, "Argument must be positive");
CCScheduler::sharedScheduler()->scheduleSelector(selector, this, interval, !m_bIsRunning);

View File

@ -81,6 +81,11 @@ protected:
*/
virtual void deleteBackward() {}
/**
@brief Called by CCIMEDispatcher for get text which delegate already has.
*/
virtual const char * getContentText() { return 0; }
//////////////////////////////////////////////////////////////////////////
// keyboard show/hide notification
//////////////////////////////////////////////////////////////////////////

View File

@ -57,6 +57,11 @@ public:
*/
void dispatchDeleteBackward();
/**
@brief get the content text, which current CCIMEDelegate which attached with IME has.
*/
const char * getContentText();
//////////////////////////////////////////////////////////////////////////
// dispatch keyboard notification
//////////////////////////////////////////////////////////////////////////

View File

@ -141,7 +141,7 @@ protected:
virtual bool canDetachWithIME();
virtual void insertText(const char * text, int len);
virtual void deleteBackward();
virtual const char * getContentText();
private:
class LengthStack;
LengthStack * m_pLens;

View File

@ -376,6 +376,18 @@ extern "C"
cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
}
jstring Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeGetContentText()
{
JNIEnv * env = 0;
if (gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || ! env)
{
return 0;
}
const char * pszText = cocos2d::CCIMEDispatcher::sharedDispatcher()->getContentText();
return env->NewStringUTF(pszText);
}
//////////////////////////////////////////////////////////////////////////
// get package name
//////////////////////////////////////////////////////////////////////////

View File

@ -239,6 +239,16 @@ void CCIMEDispatcher::dispatchDeleteBackward()
} while (0);
}
const char * CCIMEDispatcher::getContentText()
{
const char * pszContentText = 0;
if (m_pImpl && m_pImpl->m_DelegateWithIme)
{
pszContentText = m_pImpl->m_DelegateWithIme->getContentText();
}
return (pszContentText) ? pszContentText : "";
}
//////////////////////////////////////////////////////////////////////////
// dispatch keyboard message
//////////////////////////////////////////////////////////////////////////

View File

@ -246,6 +246,11 @@ void CCTextFieldTTF::deleteBackward()
setString(sText.c_str());
}
const char * CCTextFieldTTF::getContentText()
{
return m_pInputText->c_str();
}
void CCTextFieldTTF::draw()
{
if (m_pDelegate && m_pDelegate->onDraw(this))

View File

@ -11,7 +11,8 @@ public final class R {
public static final class attr {
}
public static final class id {
public static final int test_demo_gl_surfaceview=0x7f040000;
public static final int test_demo_gl_surfaceview=0x7f040001;
public static final int textField=0x7f040000;
}
public static final class layout {
public static final int test_demo=0x7f020000;

View File

@ -2,7 +2,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
android:orientation="vertical" android:layout_gravity="bottom">
<EditText android:id="@+id/textField" android:layout_height="wrap_content" android:layout_weight="0" android:layout_width="fill_parent"></EditText>
<org.cocos2dx.lib.Cocos2dxGLSurfaceView
android:id="@+id/test_demo_gl_surfaceview"

View File

@ -2,99 +2,93 @@ package org.cocos2dx.lib;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Build.VERSION;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
class Cocos2dxInputConnection extends BaseInputConnection {
private static final boolean mDebug = false;
void LogD(String msg) {
if (mDebug) {
Log.d("Cocos2dxInputConnection", msg);
}
class TextInputWraper implements TextWatcher, OnEditorActionListener {
private static final Boolean debug = false;
private void LogD(String msg) {
if (debug) Log.d("TextInputFilter", msg);
}
private Cocos2dxGLSurfaceView mView;
private String mLastCommit;
Cocos2dxInputConnection(Cocos2dxGLSurfaceView view) {
super(view, false);
mView = view;
mLastCommit = "";
LogD("SDK Version(" + VERSION.SDK_INT + "):\n "
+ "Release: " + VERSION.RELEASE + "\n "
+ "Incremental: " + VERSION.INCREMENTAL + "\n "
+ "CodeName: " + VERSION.CODENAME);
}
private Cocos2dxGLSurfaceView mMainView;
private String mText;
private String mOriginText;
private Boolean isFullScreenEdit() {
InputMethodManager imm = (InputMethodManager)mMainView.getTextField().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.isFullscreenMode();
}
public TextInputWraper(Cocos2dxGLSurfaceView view) {
mMainView = view;
}
public void setOriginText(String text) {
mOriginText = text;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
super.commitText(text, newCursorPosition);
if (null != mView) {
final String insertText = text.toString();
mLastCommit = insertText;
mView.insertText(insertText);
LogD("commitText: " + insertText);
public void afterTextChanged(Editable s) {
if (isFullScreenEdit()) {
return;
}
return true;
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request,
int flags) {
LogD("getExtractedText: " + request.toString() + "," + flags);
return new ExtractedText();
}
@Override
public boolean performEditorAction(int editorAction) {
LogD("performEditorAction: " + editorAction);
if (null != mView) {
final String insertText = "\n";
mLastCommit = insertText;
mView.insertText(insertText);
LogD("afterTextChanged: " + s);
int nModified = s.length() - mText.length();
if (nModified > 0) {
final String insertText = s.subSequence(mText.length(), s.length()).toString();
mMainView.insertText(insertText);
LogD("insertText(" + insertText + ")");
}
return true;
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
LogD("sendKeyEvent: " + event.toString());
super.sendKeyEvent(event);
if (null != mView) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DEL:
if (KeyEvent.ACTION_UP == event.getAction()) {
mView.deleteBackward();
}
break;
else {
for (; nModified < 0; ++nModified) {
mMainView.deleteBackward();
LogD("deleteBackward");
}
}
return true;
mText = s.toString();
}
@Override
public boolean finishComposingText() {
LogD("finishComposingText");
mLastCommit = "";
return super.finishComposingText();
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
LogD("beforeTextChanged(" + s + ")start: " + start + ",count: " + count + ",after: " + after);
mText = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public CharSequence getTextBeforeCursor(int n, int flags) {
LogD("getTextBeforeCursor");
return mLastCommit;
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (mMainView.getTextField() == v && isFullScreenEdit()) {
// user press the action button, delete all old text and insert new text
for (int i = mOriginText.length(); i > 0; --i) {
mMainView.deleteBackward();
LogD("deleteBackward");
}
String text = v.getText().toString();
if ('\n' != text.charAt(text.length() - 1)) {
text += '\n';
}
final String insertText = text;
mMainView.insertText(insertText);
LogD("insertText(" + insertText + ")");
}
return false;
}
}
@ -104,8 +98,9 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
private static final String TAG = Cocos2dxGLSurfaceView.class.getCanonicalName();
private Cocos2dxRenderer mRenderer;
private final boolean debug = false;
private static final boolean debug = false;
///////////////////////////////////////////////////////////////////////////
// for initialize
///////////////////////////////////////////////////////////////////////////
@ -123,6 +118,38 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
mRenderer = new Cocos2dxRenderer();
setFocusableInTouchMode(true);
setRenderer(mRenderer);
textInputWraper = new TextInputWraper(this);
handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case HANDLER_OPEN_IME_KEYBOARD:
if (null != mTextField && mTextField.requestFocus()) {
mTextField.removeTextChangedListener(textInputWraper);
mTextField.setText("");
String text = (String)msg.obj;
mTextField.append(text);
textInputWraper.setOriginText(text);
mTextField.addTextChangedListener(textInputWraper);
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mTextField, 0);
Log.d("GLSurfaceView", "showSoftInput");
}
break;
case HANDLER_CLOSE_IME_KEYBOARD:
if (null != mTextField) {
mTextField.removeTextChangedListener(textInputWraper);
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mTextField.getWindowToken(), 0);
Log.d("GLSurfaceView", "HideSoftInput");
}
break;
}
}
};
mainView = this;
}
@ -151,46 +178,44 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView {
///////////////////////////////////////////////////////////////////////////
// for text input
///////////////////////////////////////////////////////////////////////////
private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
private static Handler handler;
private static TextInputWraper textInputWraper;
private TextView mTextField;
public TextView getTextField() {
return mTextField;
}
public void setTextField(TextView view) {
mTextField = view;
if (null != mTextField && null != textInputWraper) {
LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mTextField.getLayoutParams();
linearParams.height = 0;
mTextField.setLayoutParams(linearParams);
mTextField.setOnEditorActionListener(textInputWraper);
}
}
public static void openIMEKeyboard() {
if (null == mainView) {
return;
}
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
imm.showSoftInput(mainView, 0);
}
public static void closeIMEKeyboard() {
if (null == mainView) {
return;
}
InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
imm.hideSoftInputFromWindow(mainView.getWindowToken(), 0);
}
private Cocos2dxInputConnection ic;
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT;
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
outAttrs.initialSelStart = -1;
outAttrs.initialSelEnd = -1;
outAttrs.initialCapsMode = 1;
if (null == ic)
{
ic = new Cocos2dxInputConnection(this);
}
Message msg = new Message();
msg.what = HANDLER_OPEN_IME_KEYBOARD;
msg.obj = mainView.getContentText();
handler.sendMessage(msg);
return ic;
}
private String getContentText() {
return mRenderer.getContentText();
}
public static void closeIMEKeyboard() {
Message msg = new Message();
msg.what = HANDLER_CLOSE_IME_KEYBOARD;
handler.sendMessage(msg);
}
public void insertText(final String text) {
queueEvent(new Runnable() {
@Override

View File

@ -96,7 +96,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
public void handleDeleteBackward() {
nativeDeleteBackward();
}
public String getContentText() {
return nativeGetContentText();
}
private static native void nativeInsertText(String text);
private static native void nativeDeleteBackward();
private static native String nativeGetContentText();
}

View File

@ -4,10 +4,11 @@ import org.cocos2dx.lib.Cocos2dxActivity;
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
import android.os.Bundle;
import android.widget.EditText;
public class TestsDemo extends Cocos2dxActivity{
private Cocos2dxGLSurfaceView mGLView;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@ -17,7 +18,8 @@ public class TestsDemo extends Cocos2dxActivity{
setContentView(R.layout.test_demo);
mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.test_demo_gl_surfaceview);
mGLView.setTextField((EditText)findViewById(R.id.textField));
// Get the size of the mGLView after the layout happens
mGLView.post(new Runnable() {