diff --git a/HelloWorld/AppDelegate.cpp b/HelloWorld/AppDelegate.cpp index 914358fca8..872cc10232 100644 --- a/HelloWorld/AppDelegate.cpp +++ b/HelloWorld/AppDelegate.cpp @@ -69,7 +69,7 @@ bool AppDelegate::applicationDidFinishLaunching() // enable High Resource Mode(2x, such as iphone4) and maintains low resource on other devices. // pDirector->enableRetinaDisplay(true); - // sets landscape mode + // sets opengl landscape mode pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); // turn on display FPS diff --git a/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java b/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java index 4477fbb0fd..15c61742ca 100644 --- a/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java +++ b/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java @@ -2,17 +2,146 @@ package org.cocos2dx.lib; import android.content.Context; import android.opengl.GLSurfaceView; +import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.ViewGroup.LayoutParams; +import android.view.inputmethod.CompletionInfo; +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; + +class Cocos2dxInputConnection implements InputConnection { + + @Override + public boolean beginBatchEdit() { + return false; + } + + @Override + public boolean clearMetaKeyStates(int states) { + return false; + } + + @Override + public boolean commitCompletion(CompletionInfo text) { + return false; + } + + @Override + public boolean commitText(CharSequence text, int newCursorPosition) { + if (null != mView) { + final String insertText = text.toString(); + mView.insertText(insertText); + } + return false; + } + + @Override + public boolean deleteSurroundingText(int leftLength, int rightLength) { + return false; + } + + @Override + public boolean endBatchEdit() { + return false; + } + + @Override + public boolean finishComposingText() { + return false; + } + + @Override + public int getCursorCapsMode(int reqModes) { + return 0; + } + + @Override + public ExtractedText getExtractedText(ExtractedTextRequest request, + int flags) { + return null; + } + + @Override + public CharSequence getTextAfterCursor(int n, int flags) { + return null; + } + + @Override + public CharSequence getTextBeforeCursor(int n, int flags) { + return null; + } + + @Override + public boolean performContextMenuAction(int id) { + return false; + } + + @Override + public boolean performEditorAction(int editorAction) { + if (null != mView) { + final String insertText = "\n"; + mView.insertText(insertText); + } + return false; + } + + @Override + public boolean performPrivateCommand(String action, Bundle data) { + return false; + } + + @Override + public boolean reportFullscreenMode(boolean enabled) { + return false; + } + + @Override + public boolean sendKeyEvent(KeyEvent event) { + if (null != mView) { + switch (event.getKeyCode()) { + + case KeyEvent.KEYCODE_DEL: + mView.deleteBackward(); + break; + } + } + return false; + } + + @Override + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return false; + } + + @Override + public boolean setSelection(int start, int end) { + return false; + } + + public void setGLSurfaceView(Cocos2dxGLSurfaceView view) { + mView = view; + } + + private Cocos2dxGLSurfaceView mView; +} public class Cocos2dxGLSurfaceView extends GLSurfaceView { - private static final String TAG = Cocos2dxGLSurfaceView.class - .getCanonicalName(); + + static private Cocos2dxGLSurfaceView mainView; + + private static final String TAG = Cocos2dxGLSurfaceView.class.getCanonicalName(); private Cocos2dxRenderer mRenderer; private final boolean debug = false; + /////////////////////////////////////////////////////////////////////////// + // for initialize + /////////////////////////////////////////////////////////////////////////// public Cocos2dxGLSurfaceView(Context context) { super(context); initView(); @@ -27,6 +156,7 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView { mRenderer = new Cocos2dxRenderer(); setFocusableInTouchMode(true); setRenderer(mRenderer); + mainView = this; } public void onPause(){ @@ -51,6 +181,83 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView { }); } + /////////////////////////////////////////////////////////////////////////// + // for text input + /////////////////////////////////////////////////////////////////////////// + + 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); + } + + @Override + public boolean onCheckIsTextEditor() { + if (null == mainView) + { + return false; + } + return true; + } + + private Cocos2dxInputConnection ic; + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + if (onCheckIsTextEditor()) { + + outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT; + outAttrs.imeOptions = EditorInfo.IME_NULL; + outAttrs.initialSelStart = -1; + outAttrs.initialSelEnd = -1; + outAttrs.initialCapsMode = 0; + + if (null == ic) + { + ic = new Cocos2dxInputConnection(); + ic.setGLSurfaceView(this); + } + return ic; + } + return null; + } + + public void insertText(final String text) { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleInsertText(text); + } + }); + } + + public void deleteBackward() { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleDeleteBackward(); + } + }); + } + /////////////////////////////////////////////////////////////////////////// + // for touch event + /////////////////////////////////////////////////////////////////////////// + public boolean onTouchEvent(final MotionEvent event) { // these data are used in ACTION_MOVE and ACTION_CANCEL final int pointerNumber = event.getPointerCount(); diff --git a/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java b/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java index 06f389d65b..d56651c6f4 100644 --- a/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java +++ b/HelloWorld/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java @@ -75,7 +75,6 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer { public static void setAnimationInterval(double interval){ animationInterval = (long)(interval * NANOSECONDSPERSECOND); } - private static native void nativeTouchesBegin(int id, float x, float y); private static native void nativeTouchesEnd(int id, float x, float y); private static native void nativeTouchesMove(int[] id, float[] x, float[] y); @@ -85,4 +84,19 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer { private static native void nativeInit(int w, int h); private static native void nativeOnPause(); private static native void nativeOnResume(); + + ///////////////////////////////////////////////////////////////////////////////// + // handle input method edit message + ///////////////////////////////////////////////////////////////////////////////// + + public void handleInsertText(final String text) { + nativeInsertText(text); + } + + public void handleDeleteBackward() { + nativeDeleteBackward(); + } + + private static native void nativeInsertText(String text); + private static native void nativeDeleteBackward(); } diff --git a/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id b/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id index e1458e55c7..0cc41ae415 100644 --- a/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -4b1a0a89eeffc4ac07d3adecd95b38b431f8cd5c \ No newline at end of file +3300607858936d3cd32e8d541a02eb4464613808 \ No newline at end of file diff --git a/cocos2dx/Android.mk b/cocos2dx/Android.mk index 20040a2a4d..72753ae53e 100644 --- a/cocos2dx/Android.mk +++ b/cocos2dx/Android.mk @@ -83,6 +83,8 @@ support/image_support/TGAlib.cpp \ support/zip_support/ZipUtils.cpp \ support/zip_support/ioapi.cpp \ support/zip_support/unzip.cpp \ +text_input_node/CCIMEDispatcher.cpp \ +text_input_node/CCTextFieldTTF.cpp \ textures/CCTexture2D.cpp \ textures/CCTextureAtlas.cpp \ textures/CCTextureCache.cpp \ @@ -136,4 +138,4 @@ LOCAL_LDLIBS := -L$(LOCAL_PATH)/platform/third_party/android/libraries \ # define the macro to compile through support/zip_support/ioapi.c LOCAL_CFLAGS := -DUSE_FILE32API -include $(BUILD_SHARED_LIBRARY) \ No newline at end of file +include $(BUILD_SHARED_LIBRARY) diff --git a/cocos2dx/include/CCIMEDelegate.h b/cocos2dx/include/CCIMEDelegate.h new file mode 100644 index 0000000000..be9ad903d1 --- /dev/null +++ b/cocos2dx/include/CCIMEDelegate.h @@ -0,0 +1,98 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CC_IME_DELEGATE_H__ +#define __CC_IME_DELEGATE_H__ + +#include "CCGeometry.h" + +NS_CC_BEGIN; + +typedef struct +{ + CCRect begin; // the soft keyboard rectangle when animatin begin + CCRect end; // the soft keyboard rectangle when animatin end + float duration; // the soft keyboard animation duration +} CCIMEKeyboardNotificationInfo; + +/** +@brief Input method editor delegate. +*/ +class CC_DLL CCIMEDelegate +{ +public: + virtual ~CCIMEDelegate(); + + virtual bool attachWithIME(); + virtual bool detachWithIME(); + +protected: + friend class CCIMEDispatcher; + + /** + @brief Decide the delegate instance is ready for receive ime message or not. + + Called by CCIMEDispatcher. + */ + virtual bool canAttachWithIME() { return false; } + /** + @brief When the delegate detach with IME, this method call by CCIMEDispatcher. + */ + virtual void didAttachWithIME() {} + + /** + @brief Decide the delegate instance can stop receive ime message or not. + */ + virtual bool canDetachWithIME() { return false; } + + /** + @brief When the delegate detach with IME, this method call by CCIMEDispatcher. + */ + virtual void didDetachWithIME() {} + + /** + @brief Called by CCIMEDispatcher when some text input from IME. + */ + virtual void insertText(const char * text, int len) {} + + /** + @brief Called by CCIMEDispatcher when user clicked the backward key. + */ + virtual void deleteBackward() {} + + ////////////////////////////////////////////////////////////////////////// + // keyboard show/hide notification + ////////////////////////////////////////////////////////////////////////// + virtual void keyboardWillShow(CCIMEKeyboardNotificationInfo& info) {} + virtual void keyboardDidShow(CCIMEKeyboardNotificationInfo& info) {} + virtual void keyboardWillHide(CCIMEKeyboardNotificationInfo& info) {} + virtual void keyboardDidHide(CCIMEKeyboardNotificationInfo& info) {} + +protected: + CCIMEDelegate(); +}; + +NS_CC_END; + +#endif // __CC_IME_DELEGATE_H__ diff --git a/cocos2dx/include/CCIMEDispatcher.h b/cocos2dx/include/CCIMEDispatcher.h new file mode 100644 index 0000000000..515c02677a --- /dev/null +++ b/cocos2dx/include/CCIMEDispatcher.h @@ -0,0 +1,98 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CC_IME_DISPATCHER_H__ +#define __CC_IME_DISPATCHER_H__ + +#include "CCIMEDelegate.h" + +NS_CC_BEGIN; + +/** +@brief Input Method Edit Message Dispatcher. +*/ +class CC_DLL CCIMEDispatcher +{ +public: + ~CCIMEDispatcher(); + + /** + @brief Returns the shared CCIMEDispatcher object for the system. + */ + static CCIMEDispatcher* sharedDispatcher(); + +// /** +// @brief Release all CCIMEDelegates from shared dispatcher. +// */ +// static void purgeSharedDispatcher(); + + /** + @brief dispatch the input text from ime + */ + void dispatchInsertText(const char * pText, int nLen); + + /** + @brief dispatch the delete backward operation + */ + void dispatchDeleteBackward(); + + ////////////////////////////////////////////////////////////////////////// + // dispatch keyboard notification + ////////////////////////////////////////////////////////////////////////// + void dispatchKeyboardWillShow(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardDidShow(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardWillHide(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardDidHide(CCIMEKeyboardNotificationInfo& info); + +protected: + friend class CCIMEDelegate; + + /** + @brief add delegate to concern ime msg + */ + void addDelegate(CCIMEDelegate * pDelegate); + + /** + @brief attach the pDeleate with ime. + @return If the old delegate can detattach with ime and the new delegate + can attach with ime, return true, otherwise return false. + */ + bool attachDelegateWithIME(CCIMEDelegate * pDelegate); + bool detachDelegateWithIME(CCIMEDelegate * pDelegate); + + /** + @brief remove the delegate from the delegates who concern ime msg + */ + void removeDelegate(CCIMEDelegate * pDelegate); + +private: + CCIMEDispatcher(); + + class Impl; + Impl * m_pImpl; +}; + +NS_CC_END; + +#endif // __CC_IME_DISPATCHER_H__ diff --git a/cocos2dx/include/CCTextFieldTTF.h b/cocos2dx/include/CCTextFieldTTF.h new file mode 100644 index 0000000000..bcf0a73959 --- /dev/null +++ b/cocos2dx/include/CCTextFieldTTF.h @@ -0,0 +1,102 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CC_TEXT_FIELD_H__ +#define __CC_TEXT_FIELD_H__ + +#include "CCLabelTTF.h" +#include "CCIMEDelegate.h" +#include "CCTouchDelegateProtocol.h" + +NS_CC_BEGIN; + +/** +@brief A simple text input field with system TTF font. +*/ + +class CC_DLL CCTextFieldTTF : public CCLabelTTF, public CCIMEDelegate//, public CCTargetedTouchDelegate +{ +public: + CCTextFieldTTF(); + virtual ~CCTextFieldTTF(); + + //char * description(); + + /** creates a CCTextFieldTTF from a fontname, alignment, dimension and font size */ + static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + /** creates a CCLabelTTF from a fontname and font size */ + static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize); + /** initializes the CCTextFieldTTF with a font name, alignment, dimension and font size */ + bool initWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + /** initializes the CCTextFieldTTF with a font name and font size */ + bool initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize); + + /** + @brief Open keyboard and receive input text. + */ + virtual bool attachWithIME(); + + /** + @brief End text input and close keyboard. + */ + virtual bool detachWithIME(); + + ////////////////////////////////////////////////////////////////////////// + // properties + ////////////////////////////////////////////////////////////////////////// + + // input text property +public: + virtual void setString(const char *text); + virtual const char* getString(void); +protected: + std::string * m_pInputText; + + // place holder text property + // place holder text displayed when there is no text in the text field. +public: + virtual void setPlaceHolder(const char * text); + virtual const char * getPlaceHolder(void); +protected: + std::string * m_pPlaceHolder; + bool m_bLock; // when insertText or deleteBackward called, m_bLock is true +protected: + + ////////////////////////////////////////////////////////////////////////// + // CCIMEDelegate interface + ////////////////////////////////////////////////////////////////////////// + + virtual bool canAttachWithIME(); + virtual bool canDetachWithIME(); + virtual void insertText(const char * text, int len); + virtual void deleteBackward(); + +private: + class LengthStack; + LengthStack * m_pLens; +}; + +NS_CC_END; + +#endif // __CC_TEXT_FIELD_H__ \ No newline at end of file diff --git a/cocos2dx/include/CCTouchDelegateProtocol.h b/cocos2dx/include/CCTouchDelegateProtocol.h index 0fd2a99e3c..ded8f5320e 100644 --- a/cocos2dx/include/CCTouchDelegateProtocol.h +++ b/cocos2dx/include/CCTouchDelegateProtocol.h @@ -57,8 +57,8 @@ public: virtual void keep(void) {} virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { return false;}; - // optional + virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {} virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {} virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {} diff --git a/cocos2dx/include/cocos2d.h b/cocos2dx/include/cocos2d.h index 1dc4478015..0fd9c45a0c 100644 --- a/cocos2dx/include/cocos2d.h +++ b/cocos2dx/include/cocos2d.h @@ -83,6 +83,7 @@ THE SOFTWARE. #include "CCTouchDispatcher.h" #include "CCDrawingPrimitives.h" #include "CCScheduler.h" +#include "CCTextFieldTTF.h" // // cocoa includes diff --git a/cocos2dx/label_nodes/CCLabelTTF.cpp b/cocos2dx/label_nodes/CCLabelTTF.cpp index ca25edf7b1..6b9abef6a3 100644 --- a/cocos2dx/label_nodes/CCLabelTTF.cpp +++ b/cocos2dx/label_nodes/CCLabelTTF.cpp @@ -50,7 +50,7 @@ namespace cocos2d{ pRet->autorelease(); return pRet; } - CC_SAFE_DELETE(pRet) + CC_SAFE_DELETE(pRet); return NULL; } CCLabelTTF * CCLabelTTF::labelWithString(const char *label, const char *fontName, float fontSize) @@ -61,7 +61,7 @@ namespace cocos2d{ pRet->autorelease(); return pRet; } - CC_SAFE_DELETE(pRet) + CC_SAFE_DELETE(pRet); return NULL; } diff --git a/cocos2dx/platform/android/CCEGLView_android.cpp b/cocos2dx/platform/android/CCEGLView_android.cpp index 5bde12fec1..159d4b75d4 100644 --- a/cocos2dx/platform/android/CCEGLView_android.cpp +++ b/cocos2dx/platform/android/CCEGLView_android.cpp @@ -28,6 +28,7 @@ THE SOFTWARE. #include "CCDirector.h" #include "ccMacros.h" #include "CCTouchDispatcher.h" +#include "Cocos2dJni.h" #include @@ -127,21 +128,21 @@ void CCEGLView::setContentScaleFactor(float contentScaleFactor) void CCEGLView::setViewPortInPoints(float x, float y, float w, float h) { - if (m_bNotHVGA) - { - float factor = m_fScreenScaleFactor / CC_CONTENT_SCALE_FACTOR(); - glViewport((GLint)(x * factor) + m_rcViewPort.origin.x, - (GLint)(y * factor) + m_rcViewPort.origin.y, - (GLint)(w * factor), - (GLint)(h * factor)); - } - else - { - glViewport((GLint)x, - (GLint)y, - (GLint)w, - (GLint)h); - } + if (m_bNotHVGA) + { + float factor = m_fScreenScaleFactor / CC_CONTENT_SCALE_FACTOR(); + glViewport((GLint)(x * factor) + m_rcViewPort.origin.x, + (GLint)(y * factor) + m_rcViewPort.origin.y, + (GLint)(w * factor), + (GLint)(h * factor)); + } + else + { + glViewport((GLint)x, + (GLint)y, + (GLint)w, + (GLint)h); + } } CCEGLView& CCEGLView::sharedOpenGLView() @@ -157,15 +158,21 @@ float CCEGLView::getScreenScaleFactor() CCRect CCEGLView::getViewPort() { - if (m_bNotHVGA) - { - return m_rcViewPort; - } - else - { - CCRect rect(0, 0, 0, 0); - return rect; - } + if (m_bNotHVGA) + { + return m_rcViewPort; + } + else + { + CCRect rect(0, 0, 0, 0); + return rect; + } +} + +void CCEGLView::setIMEKeyboardState(bool bOpen) +{ + + setKeyboardStateJNI((int)bOpen); } } // end of namespace cocos2d diff --git a/cocos2dx/platform/android/CCEGLView_android.h b/cocos2dx/platform/android/CCEGLView_android.h index 187727366f..40b4f4a066 100644 --- a/cocos2dx/platform/android/CCEGLView_android.h +++ b/cocos2dx/platform/android/CCEGLView_android.h @@ -60,6 +60,7 @@ public: void setViewPortInPoints(float x, float y, float w, float h); CCRect getViewPort(); float getScreenScaleFactor(); + void setIMEKeyboardState(bool bOpen); // static function /** diff --git a/cocos2dx/platform/android/Cocos2dJni.cpp b/cocos2dx/platform/android/Cocos2dJni.cpp index 5ef1081df0..f3a60676e8 100644 --- a/cocos2dx/platform/android/Cocos2dJni.cpp +++ b/cocos2dx/platform/android/Cocos2dJni.cpp @@ -31,6 +31,8 @@ THE SOFTWARE. #include "CCGeometry.h" #include "CCAccelerometer.h" #include "CCApplication.h" +#include "CCIMEDispatcher.h" +#include "platform/android/CCAccelerometer_android.h" #include #if 0 @@ -44,24 +46,73 @@ using namespace cocos2d; extern "C" { + ////////////////////////////////////////////////////////////////////////// + // java vm helper function + ////////////////////////////////////////////////////////////////////////// - #define MAX_TOUCHES 5 - static CCTouch *s_pTouches[MAX_TOUCHES] = { NULL }; + JavaVM *gJavaVM = NULL; - // handle accelerometer changes + jint JNI_OnLoad(JavaVM *vm, void *reserved) + { + gJavaVM = vm; + return JNI_VERSION_1_4; + } - void Java_org_cocos2dx_lib_Cocos2dxAccelerometer_onSensorChanged(JNIEnv* env, jobject thiz, jfloat x, jfloat y, jfloat z, jlong timeStamp) - { - // We need to invert to make it compatible with iOS. - CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort(); - float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor(); - cocos2d::CCAccelerometer::sharedAccelerometer()->update((x - rcRect.origin.x) / fScreenScaleFactor, - (y - rcRect.origin.y) / fScreenScaleFactor, - z, - timeStamp); - } + struct TMethodJNI + { + JNIEnv * env; + jclass classID; + jmethodID methodID; + }; + static bool getMethodID(struct TMethodJNI& t, const char *className, const char *methodName, const char *paramCode) + { + bool ret = 0; + do + { + if (gJavaVM->GetEnv((void**)&t.env, JNI_VERSION_1_4) != JNI_OK) + { + LOGD("Failed to get the environment using GetEnv()"); + break; + } - // handle touch event + if (gJavaVM->AttachCurrentThread(&t.env, 0) < 0) + { + LOGD("Failed to get the environment using AttachCurrentThread()"); + break; + } + + t.classID = t.env->FindClass(className); + if (! t.classID) + { + LOGD("Failed to find class of %s", className); + break; + } + + t.methodID = t.env->GetStaticMethodID(t.classID, methodName, paramCode); + if (! t.methodID) + { + LOGD("Failed to find method id of %s", methodName); + break; + } + ret = true; + } while (0); + + return ret; + } + + ////////////////////////////////////////////////////////////////////////// + // native renderer + ////////////////////////////////////////////////////////////////////////// + + #define MAX_TOUCHES 5 + static CCTouch *s_pTouches[MAX_TOUCHES] = { NULL }; + + void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) + { + cocos2d::CCDirector::sharedDirector()->mainLoop(); + } + + // handle touch event void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv* env, jobject thiz, jint id, jfloat x, jfloat y) { CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort(); @@ -211,6 +262,21 @@ extern "C" return JNI_FALSE; } + ////////////////////////////////////////////////////////////////////////// + // handle accelerometer changes + ////////////////////////////////////////////////////////////////////////// + + void Java_org_cocos2dx_lib_Cocos2dxAccelerometer_onSensorChanged(JNIEnv* env, jobject thiz, jfloat x, jfloat y, jfloat z, jlong timeStamp) + { + // We need to invert to make it compatible with iOS. + CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort(); + float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor(); + cocos2d::CCAccelerometer::sharedAccelerometer()->update((x - rcRect.origin.x) / fScreenScaleFactor, + (y - rcRect.origin.y) / fScreenScaleFactor, + z, + timeStamp); + } + void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath) { const char* str; @@ -222,72 +288,29 @@ extern "C" } } - // record the java vm - - JavaVM *gJavaVM = NULL; - jclass classOfCocos2dxActivity = 0; - JNIEnv *env = 0; - - jint JNI_OnLoad(JavaVM *vm, void *reserved) - { - gJavaVM = vm; - return JNI_VERSION_1_4; - } - - static jmethodID getMethodID(const char *methodName, const char *paramCode) - { - jmethodID ret = 0; - - // get jni environment and java class for Cocos2dxActivity - if (gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) - { - LOGD("Failed to get the environment using GetEnv()"); - return 0; - } - - if (gJavaVM->AttachCurrentThread(&env, 0) < 0) - { - LOGD("Failed to get the environment using AttachCurrentThread()"); - return 0; - } - - classOfCocos2dxActivity = env->FindClass("org/cocos2dx/lib/Cocos2dxActivity"); - if (! classOfCocos2dxActivity) - { - LOGD("Failed to find class of org/cocos2dx/lib/Cocos2dxActivity"); - return 0; - } - - if (env != 0 && classOfCocos2dxActivity != 0) - { - ret = env->GetStaticMethodID(classOfCocos2dxActivity, methodName, paramCode); - } - - if (! ret) - { - LOGD("get method id of %s error", methodName); - } - - return ret; - } void enableAccelerometerJNI() { - jmethodID methodID = getMethodID("enableAccelerometer", "()V"); - - if (methodID) + TMethodJNI t; + if (getMethodID(t + , "org/cocos2dx/lib/Cocos2dxActivity" + , "enableAccelerometer" + , "()V")) { - env->CallStaticVoidMethod(classOfCocos2dxActivity, methodID); + t.env->CallStaticVoidMethod(t.classID, t.methodID); } } void disableAccelerometerJNI() { - jmethodID methodID = getMethodID("disableAccelerometer", "()V"); + TMethodJNI t; - if (methodID) + if (getMethodID(t + , "org/cocos2dx/lib/Cocos2dxActivity" + , "disableAccelerometer" + , "()V")) { - env->CallStaticVoidMethod(classOfCocos2dxActivity, methodID); + t.env->CallStaticVoidMethod(t.classID, t.methodID); } } @@ -298,30 +321,58 @@ extern "C" return; } - jmethodID methodID = getMethodID("showMessageBox", "(Ljava/lang/String;Ljava/lang/String;)V"); - - if (methodID) + TMethodJNI t; + if (getMethodID(t + , "org/cocos2dx/lib/Cocos2dxActivity" + , "showMessageBox" + , "(Ljava/lang/String;Ljava/lang/String;)V")) { jstring StringArg1; if (! pszTitle) { - StringArg1 = env->NewStringUTF(""); + StringArg1 = t.env->NewStringUTF(""); } else { - StringArg1 = env->NewStringUTF(pszTitle); + StringArg1 = t.env->NewStringUTF(pszTitle); } - jstring StringArg2 = env->NewStringUTF(pszMsg); - env->CallStaticVoidMethod(classOfCocos2dxActivity, methodID, StringArg1, StringArg2); + jstring StringArg2 = t.env->NewStringUTF(pszMsg); + t.env->CallStaticVoidMethod(t.classID, t.methodID, StringArg1, StringArg2); } } - // native renderer + ////////////////////////////////////////////////////////////////////////// + // handle IME message + ////////////////////////////////////////////////////////////////////////// - void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) - { - cocos2d::CCDirector::sharedDirector()->mainLoop(); - } + void setKeyboardStateJNI(int bOpen) + { + TMethodJNI t; + jint open = bOpen; + if (getMethodID(t + , "org/cocos2dx/lib/Cocos2dxGLSurfaceView" + , (bOpen) ? "openIMEKeyboard" : "closeIMEKeyboard" + , "()V")) + { + t.env->CallStaticVoidMethod(t.classID, t.methodID); + } + } + + void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInsertText(JNIEnv* env, jobject thiz, jstring text) + { + jboolean isCopy = 0; + const char* pszText = env->GetStringUTFChars(text, &isCopy); + if (isCopy) + { + cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText)); + env->ReleaseStringUTFChars(text, pszText); + } + } + + void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeDeleteBackward(JNIEnv* env, jobject thiz) + { + cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(); + } } diff --git a/cocos2dx/platform/android/Cocos2dJni.h b/cocos2dx/platform/android/Cocos2dJni.h index d83aa73a0e..7cf0d83c98 100644 --- a/cocos2dx/platform/android/Cocos2dJni.h +++ b/cocos2dx/platform/android/Cocos2dJni.h @@ -33,6 +33,7 @@ extern "C" void enableAccelerometerJNI(); void disableAccelerometerJNI(); void showMessageBoxJNI(const char * pszMsg, const char * pszTitle); + void setKeyboardStateJNI(int bOpen); } #endif // __ANDROID_COCOS2D_JNI_H__ diff --git a/cocos2dx/platform/ios/CCEGLView_ios.h b/cocos2dx/platform/ios/CCEGLView_ios.h index 5c6d0decf6..0115a5f745 100644 --- a/cocos2dx/platform/ios/CCEGLView_ios.h +++ b/cocos2dx/platform/ios/CCEGLView_ios.h @@ -55,6 +55,8 @@ public: void touchesEnded(CCSet *set); void touchesCancelled(CCSet *set); + void setIMEKeyboardState(bool bOpen); + static CCEGLView& sharedOpenGLView(); private: diff --git a/cocos2dx/platform/ios/CCEGLView_ios.mm b/cocos2dx/platform/ios/CCEGLView_ios.mm index 587b5e5149..e6b62f4b12 100644 --- a/cocos2dx/platform/ios/CCEGLView_ios.mm +++ b/cocos2dx/platform/ios/CCEGLView_ios.mm @@ -111,13 +111,25 @@ void CCEGLView::touchesCancelled(CCSet *set) void CCEGLView::setViewPortInPoints(float x, float y, float w, float h) { - glViewport((GLint)x, (GLint)y, (GLint)w, (GLint)h); + glViewport((GLint)x, (GLint)y, (GLint)w, (GLint)h); +} + +void CCEGLView::setIMEKeyboardState(bool bOpen) +{ + if (bOpen) + { + [[EAGLView sharedEGLView] becomeFirstResponder]; + } + else + { + [[EAGLView sharedEGLView] resignFirstResponder]; + } } CCEGLView& CCEGLView::sharedOpenGLView() { - static CCEGLView instance; - return instance; + static CCEGLView instance; + return instance; } } // end of namespace cocos2d; diff --git a/cocos2dx/platform/ios/EAGLView.h b/cocos2dx/platform/ios/EAGLView.h index ab2019ae76..fe36d9eaf5 100755 --- a/cocos2dx/platform/ios/EAGLView.h +++ b/cocos2dx/platform/ios/EAGLView.h @@ -77,7 +77,7 @@ Copyright (C) 2008 Apple Inc. All Rights Reserved. * The view content is basically an EAGL surface you render your OpenGL scene into. * Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. */ -@interface EAGLView : UIView +@interface EAGLView : UIView { id renderer_; EAGLContext *context_; // weak ref @@ -91,12 +91,21 @@ Copyright (C) 2008 Apple Inc. All Rights Reserved. //fsaa addition BOOL multisampling_; - unsigned int requestedSamples_; + unsigned int requestedSamples_; @private - CFMutableDictionaryRef touchesIntergerDict; - unsigned int indexBitsUsed; + CFMutableDictionaryRef touchesIntergerDict; + unsigned int indexBitsUsed; + NSString * markedText_; } +@property(nonatomic, readonly) UITextPosition *beginningOfDocument; +@property(nonatomic, readonly) UITextPosition *endOfDocument; +@property(nonatomic, assign) id inputDelegate; +@property(nonatomic, readonly) UITextRange *markedTextRange; +@property (nonatomic, copy) NSDictionary *markedTextStyle; +@property(readwrite, copy) UITextRange *selectedTextRange; +@property(nonatomic, readonly) id tokenizer; + /** creates an initializes an EAGLView with a frame and 0-bit depth buffer, and a RGB565 color buffer */ + (id) viewWithFrame:(CGRect)frame; /** creates an initializes an EAGLView with a frame, a color buffer format, and 0-bit depth buffer */ @@ -142,4 +151,5 @@ Copyright (C) 2008 Apple Inc. All Rights Reserved. -(int) getHeight; -(int) getUnUsedIndex; -(void) removeUsedIndexBit:(int) index; + @end diff --git a/cocos2dx/platform/ios/EAGLView.mm b/cocos2dx/platform/ios/EAGLView.mm index 4f9213ad79..4945aeccde 100755 --- a/cocos2dx/platform/ios/EAGLView.mm +++ b/cocos2dx/platform/ios/EAGLView.mm @@ -68,6 +68,7 @@ Copyright (C) 2008 Apple Inc. All Rights Reserved. #import "CCDirector.h" #import "CCSet.h" #import "CCTouch.h" +#import "CCIMEDispatcher.h" #import "OpenGL_Internal.h" //CLASS IMPLEMENTATIONS: @@ -176,6 +177,25 @@ static cocos2d::CCTouch *s_pTouches[MAX_TOUCHES]; return self; } +- (void)didMoveToWindow; +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onUIKeyboardNotification:) + name:UIKeyboardWillShowNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onUIKeyboardNotification:) + name:UIKeyboardDidShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onUIKeyboardNotification:) + name:UIKeyboardWillHideNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onUIKeyboardNotification:) + name:UIKeyboardDidHideNotification object:nil]; + +} + -(int) getWidth { CGSize bound = [self bounds].size; @@ -491,4 +511,306 @@ static cocos2d::CCTouch *s_pTouches[MAX_TOUCHES]; cocos2d::CCDirector::sharedDirector()->getOpenGLView()->touchesCancelled(&set); } +#pragma mark - +#pragma mark UIView - Responder + +- (BOOL)canBecomeFirstResponder +{ + markedText_ = nil; + return YES; +} + +#pragma mark - +#pragma mark UIKeyInput protocol + +- (BOOL)hasText +{ + return NO; +} + +- (void)insertText:(NSString *)text +{ + const char * pszText = [text cStringUsingEncoding:NSUTF8StringEncoding]; + cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText)); +} + +- (void)deleteBackward +{ + cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(); +} + +#pragma mark - +#pragma mark UITextInputTrait protocol + +-(UITextAutocapitalizationType) autocapitalizationType +{ + return UITextAutocapitalizationTypeNone; +} + +#pragma mark - +#pragma mark UITextInput protocol + +#pragma mark UITextInput - properties + +@synthesize beginningOfDocument; +@synthesize endOfDocument; +@synthesize inputDelegate; +@synthesize markedTextRange; +@synthesize markedTextStyle; +// @synthesize selectedTextRange; // must implement +@synthesize tokenizer; + +/* Text may have a selection, either zero-length (a caret) or ranged. Editing operations are + * always performed on the text from this selection. nil corresponds to no selection. */ +- (void)setSelectedTextRange:(UITextRange *)aSelectedTextRange; +{ + CCLOG("UITextRange:setSelectedTextRange"); +} +- (UITextRange *)selectedTextRange; +{ + return [[[UITextRange alloc] init] autorelease]; +} + +#pragma mark UITextInput - Replacing and Returning Text + +- (NSString *)textInRange:(UITextRange *)range; +{ + CCLOG("textInRange"); + return nil; +} +- (void)replaceRange:(UITextRange *)range withText:(NSString *)theText; +{ + CCLOG("replaceRange"); +} + +#pragma mark UITextInput - Working with Marked and Selected Text + + + +/* If text can be selected, it can be marked. Marked text represents provisionally + * inserted text that has yet to be confirmed by the user. It requires unique visual + * treatment in its display. If there is any marked text, the selection, whether a + * caret or an extended range, always resides witihin. + * + * Setting marked text either replaces the existing marked text or, if none is present, + * inserts it from the current selection. */ + +- (void)setMarkedTextRange:(UITextRange *)markedTextRange; +{ + CCLOG("setMarkedTextRange"); +} + +- (UITextRange *)markedTextRange; +{ + CCLOG("markedTextRange"); + return nil; // Nil if no marked text. +} +- (void)setMarkedTextStyle:(NSDictionary *)markedTextStyle; +{ + CCLOG("setMarkedTextStyle"); + +} +- (NSDictionary *)markedTextStyle; +{ + CCLOG("markedTextStyle"); + return nil; +} +- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange; +{ + CCLOG("setMarkedText"); + markedText_ = markedText; +} +- (void)unmarkText; +{ + CCLOG("unmarkText"); + if (nil == markedText_) + { + return; + } + const char * pszText = [markedText_ cStringUsingEncoding:NSUTF8StringEncoding]; + cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText)); + markedText_ = nil; +} + +#pragma mark Methods for creating ranges and positions. + +- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition; +{ + CCLOG("textRangeFromPosition"); + return nil; +} +- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset; +{ + CCLOG("positionFromPosition"); + return nil; +} +- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset; +{ + CCLOG("positionFromPosition"); + return nil; +} + +/* Simple evaluation of positions */ +- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other; +{ + CCLOG("comparePosition"); + return 0; +} +- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition; +{ + CCLOG("offsetFromPosition"); + return 0; +} + +- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction; +{ + CCLOG("positionWithinRange"); + return nil; +} +- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction; +{ + CCLOG("characterRangeByExtendingPosition"); + return nil; +} + +#pragma mark Writing direction + +- (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction; +{ + CCLOG("baseWritingDirectionForPosition"); + return UITextWritingDirectionNatural; +} +- (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range; +{ + CCLOG("setBaseWritingDirection"); +} + +#pragma mark Geometry + +/* Geometry used to provide, for example, a correction rect. */ +- (CGRect)firstRectForRange:(UITextRange *)range; +{ + CCLOG("firstRectForRange"); + return CGRectNull; +} +- (CGRect)caretRectForPosition:(UITextPosition *)position; +{ + CCLOG("caretRectForPosition"); + return CGRectMake(0, 0, 0, 0); +} + +#pragma mark Hit testing + +/* JS - Find the closest position to a given point */ +- (UITextPosition *)closestPositionToPoint:(CGPoint)point; +{ + CCLOG(@"closestPositionToPoint"); + return nil; +} +- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range; +{ + CCLOG("closestPositionToPoint"); + return nil; +} +- (UITextRange *)characterRangeAtPoint:(CGPoint)point; +{ + CCLOG("characterRangeAtPoint"); + return nil; +} + +#pragma mark - +#pragma mark UIKeyboard notification + +- (void)onUIKeyboardNotification:(NSNotification *)notif; +{ + NSString * type = notif.name; + + NSDictionary* info = [notif userInfo]; + CGRect begin = [self convertRect: + [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] + fromView:self]; + CGRect end = [self convertRect: + [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] + fromView:self]; + double aniDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + + CGSize viewSize = self.frame.size; + CGFloat tmp; + + switch ([[UIApplication sharedApplication] statusBarOrientation]) + { + case UIInterfaceOrientationPortrait: + begin.origin.y = viewSize.height - begin.origin.y - begin.size.height; + end.origin.y = viewSize.height - end.origin.y - end.size.height; + break; + + case UIInterfaceOrientationPortraitUpsideDown: + begin.origin.x = viewSize.width - (begin.origin.x + begin.size.width); + end.origin.x = viewSize.width - (end.origin.x + end.size.width); + break; + + case UIInterfaceOrientationLandscapeLeft: + tmp = begin.size.width; + begin.size.width = begin.size.height; + begin.size.height = tmp; + tmp = end.size.width; + end.size.width = end.size.height; + end.size.height = tmp; + + tmp = begin.origin.x; + begin.origin.x = begin.origin.y; + begin.origin.y = viewSize.width - tmp - begin.size.height; + tmp = end.origin.x; + end.origin.x = end.origin.y; + end.origin.y = viewSize.width - tmp - end.size.height; + break; + + case UIInterfaceOrientationLandscapeRight: + tmp = begin.size.width; + begin.size.width = begin.size.height; + begin.size.height = tmp; + tmp = end.size.width; + end.size.width = end.size.height; + end.size.height = tmp; + + tmp = begin.origin.x; + begin.origin.x = begin.origin.y; + begin.origin.y = tmp; + tmp = end.origin.x; + end.origin.x = end.origin.y; + end.origin.y = tmp; + break; + + default: + break; + } + cocos2d::CCIMEKeyboardNotificationInfo notiInfo; + notiInfo.begin = cocos2d::CCRect(begin.origin.x, + begin.origin.y, + begin.size.width, + begin.size.height); + notiInfo.end = cocos2d::CCRect(end.origin.x, + end.origin.y, + end.size.width, + end.size.height); + notiInfo.duration = (float)aniDuration; + cocos2d::CCIMEDispatcher* dispatcher = cocos2d::CCIMEDispatcher::sharedDispatcher(); + if (UIKeyboardWillShowNotification == type) + { + dispatcher->dispatchKeyboardWillShow(notiInfo); + } + else if (UIKeyboardDidShowNotification == type) + { + dispatcher->dispatchKeyboardDidShow(notiInfo); + } + else if (UIKeyboardWillHideNotification == type) + { + dispatcher->dispatchKeyboardWillHide(notiInfo); + } + else if (UIKeyboardDidHideNotification == type) + { + dispatcher->dispatchKeyboardDidHide(notiInfo); + } +} + @end diff --git a/cocos2dx/platform/win32/CCEGLView_win32.cpp b/cocos2dx/platform/win32/CCEGLView_win32.cpp index 0a9cea49de..63af858d3f 100644 --- a/cocos2dx/platform/win32/CCEGLView_win32.cpp +++ b/cocos2dx/platform/win32/CCEGLView_win32.cpp @@ -32,6 +32,7 @@ THE SOFTWARE. #include "CCDirector.h" #include "CCTouch.h" #include "CCTouchDispatcher.h" +#include "CCIMEDispatcher.h" NS_CC_BEGIN; @@ -310,6 +311,42 @@ LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) } break; + case WM_CHAR: + { + if (wParam < 0x20) + { + if (VK_BACK == wParam) + { + CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(); + } + else if (VK_RETURN == wParam) + { + CCIMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1); + } + else if (VK_TAB == wParam) + { + // tab input + } + else if (VK_ESCAPE == wParam) + { + // ESC input + } + } + else if (wParam < 128) + { + // ascii char + CCIMEDispatcher::sharedDispatcher()->dispatchInsertText((const char *)&wParam, 1); + } + else + { + char szUtf8[8] = {0}; + int nLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)&wParam, 1, szUtf8, sizeof(szUtf8), NULL, NULL); + + CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(szUtf8, nLen); + } + } + break; + case WM_PAINT: BeginPaint(m_hWnd, &ps); EndPaint(m_hWnd, &ps); @@ -407,6 +444,10 @@ void CCEGLView::setViewPortInPoints(float x, float y, float w, float h) } } +void CCEGLView::setIMEKeyboardState(bool /*bOpen*/) +{ +} + HWND CCEGLView::getHWnd() { return m_hWnd; diff --git a/cocos2dx/platform/win32/CCEGLView_win32.h b/cocos2dx/platform/win32/CCEGLView_win32.h index b50fcf2504..37914b1b93 100644 --- a/cocos2dx/platform/win32/CCEGLView_win32.h +++ b/cocos2dx/platform/win32/CCEGLView_win32.h @@ -59,6 +59,8 @@ public: int setDeviceOrientation(int eOritation); void setViewPortInPoints(float x, float y, float w, float h); + void setIMEKeyboardState(bool bOpen); + // win32 platform function HWND getHWnd(); void resize(int width, int height); diff --git a/cocos2dx/proj.win32/cocos2d-win32.vcproj b/cocos2dx/proj.win32/cocos2d-win32.vcproj index 265f241892..bcea9d8bac 100644 --- a/cocos2dx/proj.win32/cocos2d-win32.vcproj +++ b/cocos2dx/proj.win32/cocos2d-win32.vcproj @@ -419,6 +419,14 @@ RelativePath="..\include\CCGL.h" > + + + + @@ -555,6 +563,10 @@ RelativePath="..\include\CCString.h" > + + @@ -1048,6 +1060,18 @@ > + + + + + + diff --git a/cocos2dx/text_input_node/CCIMEDispatcher.cpp b/cocos2dx/text_input_node/CCIMEDispatcher.cpp new file mode 100644 index 0000000000..1e21b4dad4 --- /dev/null +++ b/cocos2dx/text_input_node/CCIMEDispatcher.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#include "CCIMEDispatcher.h" + +#include + +NS_CC_BEGIN; + +////////////////////////////////////////////////////////////////////////// +// add/remove delegate in CCIMEDelegate Cons/Destructor +////////////////////////////////////////////////////////////////////////// + +CCIMEDelegate::CCIMEDelegate() +{ + CCIMEDispatcher::sharedDispatcher()->addDelegate(this); +} + +CCIMEDelegate::~CCIMEDelegate() +{ + CCIMEDispatcher::sharedDispatcher()->removeDelegate(this); +} + +bool CCIMEDelegate::attachWithIME() +{ + return CCIMEDispatcher::sharedDispatcher()->attachDelegateWithIME(this); +} + +bool CCIMEDelegate::detachWithIME() +{ + return CCIMEDispatcher::sharedDispatcher()->detachDelegateWithIME(this); +} + +////////////////////////////////////////////////////////////////////////// + +typedef std::list< CCIMEDelegate * > DelegateList; +typedef std::list< CCIMEDelegate * >::iterator DelegateIter; + +////////////////////////////////////////////////////////////////////////// +// Delegate List manage class +////////////////////////////////////////////////////////////////////////// + +class CCIMEDispatcher::Impl +{ +public: + Impl() + { + } + + ~Impl() + { + + } + + void init() + { + m_DelegateWithIme = 0; + } + + DelegateIter findDelegate(CCIMEDelegate* pDelegate) + { + DelegateIter end = m_DelegateList.end(); + for (DelegateIter iter = m_DelegateList.begin(); iter != end; ++iter) + { + if (pDelegate == *iter) + { + return iter; + } + } + return end; + } + + DelegateList m_DelegateList; + CCIMEDelegate* m_DelegateWithIme; +}; + +////////////////////////////////////////////////////////////////////////// +// Cons/Destructor +////////////////////////////////////////////////////////////////////////// + +CCIMEDispatcher::CCIMEDispatcher() +: m_pImpl(new CCIMEDispatcher::Impl) +{ + m_pImpl->init(); +} + +CCIMEDispatcher::~CCIMEDispatcher() +{ + CC_SAFE_DELETE(m_pImpl); +} + +////////////////////////////////////////////////////////////////////////// +// Add/Attach/Remove CCIMEDelegate +////////////////////////////////////////////////////////////////////////// + +void CCIMEDispatcher::addDelegate(CCIMEDelegate* pDelegate) +{ + if (! pDelegate || ! m_pImpl) + { + return; + } + if (m_pImpl->m_DelegateList.end() != m_pImpl->findDelegate(pDelegate)) + { + // pDelegate already in list + return; + } + m_pImpl->m_DelegateList.push_front(pDelegate); +} + +bool CCIMEDispatcher::attachDelegateWithIME(CCIMEDelegate * pDelegate) +{ + bool bRet = false; + do + { + CC_BREAK_IF(! m_pImpl || ! pDelegate); + + DelegateIter end = m_pImpl->m_DelegateList.end(); + DelegateIter iter = m_pImpl->findDelegate(pDelegate); + + // if pDelegate is not in delegate list, return + CC_BREAK_IF(end == iter); + + if (m_pImpl->m_DelegateWithIme) + { + // if old delegate canDetachWithIME return false + // or pDelegate canAttachWithIME return false, + // do nothing. + CC_BREAK_IF(! m_pImpl->m_DelegateWithIme->canDetachWithIME() + || ! pDelegate->canAttachWithIME()); + + // detach first + CCIMEDelegate * pOldDelegate = m_pImpl->m_DelegateWithIme; + m_pImpl->m_DelegateWithIme = 0; + pOldDelegate->didDetachWithIME(); + } + m_pImpl->m_DelegateWithIme = *iter; + pDelegate->didAttachWithIME(); + bRet = true; + } while (0); + return bRet; +} + +bool CCIMEDispatcher::detachDelegateWithIME(CCIMEDelegate * pDelegate) +{ + bool bRet = false; + do + { + CC_BREAK_IF(! m_pImpl || ! pDelegate); + + // if pDelegate is not the current delegate attached with ime, return + CC_BREAK_IF(m_pImpl->m_DelegateWithIme != pDelegate); + + CC_BREAK_IF(! pDelegate->canDetachWithIME()); + + m_pImpl->m_DelegateWithIme = 0; + pDelegate->didDetachWithIME(); + bRet = true; + } while (0); + return bRet; +} + +void CCIMEDispatcher::removeDelegate(CCIMEDelegate* pDelegate) +{ + do + { + CC_BREAK_IF(! pDelegate || ! m_pImpl); + + DelegateIter iter = m_pImpl->findDelegate(pDelegate); + DelegateIter end = m_pImpl->m_DelegateList.end(); + CC_BREAK_IF(end == iter); + + if (m_pImpl->m_DelegateWithIme) + + if (*iter == m_pImpl->m_DelegateWithIme) + { + m_pImpl->m_DelegateWithIme = 0; + } + m_pImpl->m_DelegateList.erase(iter); + } while (0); +} + +////////////////////////////////////////////////////////////////////////// +// dispatch text message +////////////////////////////////////////////////////////////////////////// + +void CCIMEDispatcher::dispatchInsertText(const char * pText, int nLen) +{ + do + { + CC_BREAK_IF(! m_pImpl || ! pText || nLen <= 0); + + // there is no delegate attach with ime + CC_BREAK_IF(! m_pImpl->m_DelegateWithIme); + + m_pImpl->m_DelegateWithIme->insertText(pText, nLen); + } while (0); +} + +void CCIMEDispatcher::dispatchDeleteBackward() +{ + do + { + CC_BREAK_IF(! m_pImpl); + + // there is no delegate attach with ime + CC_BREAK_IF(! m_pImpl->m_DelegateWithIme); + + m_pImpl->m_DelegateWithIme->deleteBackward(); + } while (0); +} + +////////////////////////////////////////////////////////////////////////// +// dispatch keyboard message +////////////////////////////////////////////////////////////////////////// + +void CCIMEDispatcher::dispatchKeyboardWillShow(CCIMEKeyboardNotificationInfo& info) +{ + if (m_pImpl) + { + CCIMEDelegate * pDelegate = 0; + DelegateIter last = m_pImpl->m_DelegateList.end(); + for (DelegateIter first = m_pImpl->m_DelegateList.begin(); first != last; ++first) + { + pDelegate = *(first); + if (pDelegate) + { + pDelegate->keyboardWillShow(info); + } + } + } +} + +void CCIMEDispatcher::dispatchKeyboardDidShow(CCIMEKeyboardNotificationInfo& info) +{ + if (m_pImpl) + { + CCIMEDelegate * pDelegate = 0; + DelegateIter last = m_pImpl->m_DelegateList.end(); + for (DelegateIter first = m_pImpl->m_DelegateList.begin(); first != last; ++first) + { + pDelegate = *(first); + if (pDelegate) + { + pDelegate->keyboardDidShow(info); + } + } + } +} + +void CCIMEDispatcher::dispatchKeyboardWillHide(CCIMEKeyboardNotificationInfo& info) +{ + if (m_pImpl) + { + CCIMEDelegate * pDelegate = 0; + DelegateIter last = m_pImpl->m_DelegateList.end(); + for (DelegateIter first = m_pImpl->m_DelegateList.begin(); first != last; ++first) + { + pDelegate = *(first); + if (pDelegate) + { + pDelegate->keyboardWillHide(info); + } + } + } +} + +void CCIMEDispatcher::dispatchKeyboardDidHide(CCIMEKeyboardNotificationInfo& info) +{ + if (m_pImpl) + { + CCIMEDelegate * pDelegate = 0; + DelegateIter last = m_pImpl->m_DelegateList.end(); + for (DelegateIter first = m_pImpl->m_DelegateList.begin(); first != last; ++first) + { + pDelegate = *(first); + if (pDelegate) + { + pDelegate->keyboardDidHide(info); + } + } + } +} + +////////////////////////////////////////////////////////////////////////// +// protected member function +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +// static member function +////////////////////////////////////////////////////////////////////////// + +CCIMEDispatcher* CCIMEDispatcher::sharedDispatcher() +{ + static CCIMEDispatcher s_instance; + return &s_instance; +} + +NS_CC_END; diff --git a/cocos2dx/text_input_node/CCTextFieldTTF.cpp b/cocos2dx/text_input_node/CCTextFieldTTF.cpp new file mode 100644 index 0000000000..6e36d7cfb2 --- /dev/null +++ b/cocos2dx/text_input_node/CCTextFieldTTF.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#include "CCTextFieldTTF.h" + +#include + +#include "CCDirector.h" +#include "CCEGLView.h" + +NS_CC_BEGIN; + +/** +@brief Use std::vector store every input text length. +*/ +class CCTextFieldTTF::LengthStack : public std::vector< unsigned short > +{ +}; + +////////////////////////////////////////////////////////////////////////// +// constructor and destructor +////////////////////////////////////////////////////////////////////////// + +CCTextFieldTTF::CCTextFieldTTF() +: m_pInputText(new std::string) +, m_pPlaceHolder(new std::string) // prevent CCLabelTTF initWithString assertion +, m_pLens(new LengthStack) +, m_bLock(false) +{ +} + +CCTextFieldTTF::~CCTextFieldTTF() +{ + CC_SAFE_DELETE(m_pInputText); + CC_SAFE_DELETE(m_pPlaceHolder); +} + +////////////////////////////////////////////////////////////////////////// +// static constructor +////////////////////////////////////////////////////////////////////////// + +CCTextFieldTTF * CCTextFieldTTF::textFieldWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize) +{ + CCTextFieldTTF *pRet = new CCTextFieldTTF(); + if(pRet && pRet->initWithPlaceHolder("", dimensions, alignment, fontName, fontSize)) + { + pRet->autorelease(); + if (placeholder) + { + pRet->setPlaceHolder(placeholder); + } + return pRet; + } + CC_SAFE_DELETE(pRet); + return NULL; +} + +CCTextFieldTTF * CCTextFieldTTF::textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize) +{ + CCTextFieldTTF *pRet = new CCTextFieldTTF(); + if(pRet && pRet->initWithString("", fontName, fontSize)) + { + pRet->autorelease(); + if (placeholder) + { + pRet->setPlaceHolder(placeholder); + } + return pRet; + } + CC_SAFE_DELETE(pRet); + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +// initialize +////////////////////////////////////////////////////////////////////////// + +bool CCTextFieldTTF::initWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize) +{ + if (placeholder) + { + CC_SAFE_DELETE(m_pPlaceHolder); + m_pPlaceHolder = new std::string(placeholder); + } + return CCLabelTTF::initWithString(m_pPlaceHolder->c_str(), dimensions, alignment, fontName, fontSize); +} +bool CCTextFieldTTF::initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize) +{ + if (placeholder) + { + CC_SAFE_DELETE(m_pPlaceHolder); + m_pPlaceHolder = new std::string(placeholder); + } + return CCLabelTTF::initWithString(m_pPlaceHolder->c_str(), fontName, fontSize); +} + +////////////////////////////////////////////////////////////////////////// +// CCIMEDelegate +////////////////////////////////////////////////////////////////////////// + +bool CCTextFieldTTF::attachWithIME() +{ + bool bRet = CCIMEDelegate::attachWithIME(); + if (bRet) + { + // open keyboard + CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView(); + if (pGlView) + { + pGlView->setIMEKeyboardState(true); + } + } + return bRet; +} + +bool CCTextFieldTTF::detachWithIME() +{ + bool bRet = CCIMEDelegate::detachWithIME(); + if (bRet) + { + // close keyboard + CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView(); + if (pGlView) + { + pGlView->setIMEKeyboardState(false); + } + } + return bRet; +} + +bool CCTextFieldTTF::canAttachWithIME() +{ + return true; +} + +bool CCTextFieldTTF::canDetachWithIME() +{ + return true; +} + +void CCTextFieldTTF::insertText(const char * text, int len) +{ + std::string sInsert(text, len); + + // insert \n means input end + int nPos = sInsert.find('\n'); + if (sInsert.npos != nPos) + { + len = nPos; + sInsert.erase(nPos); + } + if (len <= 0) + { + // close keyboard + CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView(); + if (pGlView) + { + pGlView->setIMEKeyboardState(false); + } + return; + } + + m_bLock = true; + std::string sText(*m_pInputText); + sText.append(sInsert); + m_pLens->push_back((unsigned short)len); + setString(sText.c_str()); + m_bLock = false; +} + +void CCTextFieldTTF::deleteBackward() +{ + int nStrLen = m_pInputText->length(); + if (! nStrLen) + { + // there is no string + return; + } + + m_bLock = true; + + // get the delete byte number + int nStackSize = m_pLens->size(); + unsigned short uDeleteLen = 1; // default, erase 1 byte + if (nStackSize) + { + // get the last input text size + uDeleteLen = m_pLens->at(nStackSize - 1); + m_pLens->pop_back(); + } + + // if delete all text, show space holder string + if (nStrLen <= uDeleteLen) + { + CC_SAFE_DELETE(m_pInputText); + m_pInputText = new std::string; + CCLabelTTF::setString(m_pPlaceHolder->c_str()); + return; + } + + // set new input text + std::string sText(m_pInputText->c_str(), nStrLen - uDeleteLen); + setString(sText.c_str()); + m_bLock = false; +} + +////////////////////////////////////////////////////////////////////////// +// properties +////////////////////////////////////////////////////////////////////////// + +// input text property +void CCTextFieldTTF::setString(const char *text) +{ + CC_SAFE_DELETE(m_pInputText); + if (false == m_bLock) + { + // user use this function to set string value, clear lenStack + m_pLens->clear(); + } + if (text) + { + m_pInputText = new std::string(text); + } + else + { + m_pInputText = new std::string; + } + + // if there is no input text, display placeholder instead if (! m_pInputText->length()) { CCLabelTTF::setString(m_pPlaceHolder->c_str()); } else + { + CCLabelTTF::setString(m_pInputText->c_str()); + } +} + +const char* CCTextFieldTTF::getString(void) +{ + return m_pInputText->c_str(); +} + +// place holder text property +void CCTextFieldTTF::setPlaceHolder(const char * text) +{ + CC_SAFE_DELETE(m_pPlaceHolder); + m_pPlaceHolder = (text) ? new std::string(text) : new std::string; + if (! m_pInputText->length()) + { + CCLabelTTF::setString(m_pPlaceHolder->c_str()); + } +} + +const char * CCTextFieldTTF::getPlaceHolder(void) +{ + return m_pPlaceHolder->c_str(); +} + +NS_CC_END; diff --git a/cocos2dx/textures/CCTexture2D.cpp b/cocos2dx/textures/CCTexture2D.cpp index 9913c0acf0..f919629ed5 100644 --- a/cocos2dx/textures/CCTexture2D.cpp +++ b/cocos2dx/textures/CCTexture2D.cpp @@ -111,10 +111,10 @@ CCSize CCTexture2D::getContentSizeInPixels() CCSize CCTexture2D::getContentSize() { - CCSize ret; - ret.width = m_tContentSize.width / CC_CONTENT_SCALE_FACTOR(); - ret.height = m_tContentSize.height / CC_CONTENT_SCALE_FACTOR(); - + CCSize ret; + ret.width = m_tContentSize.width / CC_CONTENT_SCALE_FACTOR(); + ret.height = m_tContentSize.height / CC_CONTENT_SCALE_FACTOR(); + return ret; } @@ -145,7 +145,7 @@ void CCTexture2D::releaseData(void *data) void* CCTexture2D::keepData(void *data, unsigned int length) { - //The texture data mustn't be saved becuase it isn't a mutable texture. + //The texture data mustn't be saved becuase it isn't a mutable texture. return data; } @@ -253,7 +253,6 @@ bool CCTexture2D::initPremultipliedATextureWithImage(CCImage *image, unsigned in unsigned char* tempData =NULL; unsigned int* inPixel32 = NULL; unsigned short* outPixel16 = NULL; - unsigned char* outPixel8 = NULL; bool hasAlpha; CCSize imageSize; CCTexture2DPixelFormat pixelFormat; diff --git a/tests/AppDelegate.cpp b/tests/AppDelegate.cpp index 1ed8fdc9fa..857e11a69c 100644 --- a/tests/AppDelegate.cpp +++ b/tests/AppDelegate.cpp @@ -69,8 +69,8 @@ bool AppDelegate::applicationDidFinishLaunching() // enable High Resource Mode(2x, such as iphone4) and maintains low resource on other devices. // pDirector->enableRetinaDisplay(true); - // sets landscape mode - pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); + // sets opengl landscape mode + // pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); // turn on display FPS pDirector->setDisplayFPS(true); diff --git a/tests/test.android/AndroidManifest.xml b/tests/test.android/AndroidManifest.xml index 0f43ca2e59..8c49e59ad2 100644 --- a/tests/test.android/AndroidManifest.xml +++ b/tests/test.android/AndroidManifest.xml @@ -7,7 +7,7 @@ android:debuggable="true"> diff --git a/tests/test.android/jni/tests/Android.mk b/tests/test.android/jni/tests/Android.mk index 4dad2674d2..07818cae51 100644 --- a/tests/test.android/jni/tests/Android.mk +++ b/tests/test.android/jni/tests/Android.mk @@ -44,6 +44,7 @@ LOCAL_SRC_FILES := main.cpp \ ../../../tests/KeypadTest/KeypadTest.cpp \ ../../../tests/LabelTest/LabelTest.cpp \ ../../../tests/LayerTest/LayerTest.cpp \ +../../../tests/TextInputTest/TextInputTest.cpp \ ../../../tests/MenuTest/MenuTest.cpp \ ../../../tests/MotionStreakTest/MotionStreakTest.cpp \ ../../../tests/ParallaxTest/ParallaxTest.cpp \ @@ -98,4 +99,4 @@ LOCAL_LDLIBS := -L$(LOCAL_PATH)/../../libs/armeabi \ # -L$(call host-path, $(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries) -lcurl include $(BUILD_SHARED_LIBRARY) - \ No newline at end of file + diff --git a/tests/test.android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java b/tests/test.android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java index 4477fbb0fd..9a3ad96000 100644 --- a/tests/test.android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java +++ b/tests/test.android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java @@ -2,17 +2,145 @@ package org.cocos2dx.lib; import android.content.Context; import android.opengl.GLSurfaceView; +import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.inputmethod.CompletionInfo; +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; + +class Cocos2dxInputConnection implements InputConnection { + + @Override + public boolean beginBatchEdit() { + return false; + } + + @Override + public boolean clearMetaKeyStates(int states) { + return false; + } + + @Override + public boolean commitCompletion(CompletionInfo text) { + return false; + } + + @Override + public boolean commitText(CharSequence text, int newCursorPosition) { + if (null != mView) { + final String insertText = text.toString(); + mView.insertText(insertText); + } + return false; + } + + @Override + public boolean deleteSurroundingText(int leftLength, int rightLength) { + return false; + } + + @Override + public boolean endBatchEdit() { + return false; + } + + @Override + public boolean finishComposingText() { + return false; + } + + @Override + public int getCursorCapsMode(int reqModes) { + return 0; + } + + @Override + public ExtractedText getExtractedText(ExtractedTextRequest request, + int flags) { + return null; + } + + @Override + public CharSequence getTextAfterCursor(int n, int flags) { + return null; + } + + @Override + public CharSequence getTextBeforeCursor(int n, int flags) { + return null; + } + + @Override + public boolean performContextMenuAction(int id) { + return false; + } + + @Override + public boolean performEditorAction(int editorAction) { + if (null != mView) { + final String insertText = "\n"; + mView.insertText(insertText); + } + return false; + } + + @Override + public boolean performPrivateCommand(String action, Bundle data) { + return false; + } + + @Override + public boolean reportFullscreenMode(boolean enabled) { + return false; + } + + @Override + public boolean sendKeyEvent(KeyEvent event) { + if (null != mView) { + switch (event.getKeyCode()) { + + case KeyEvent.KEYCODE_DEL: + mView.deleteBackward(); + break; + } + } + return false; + } + + @Override + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return false; + } + + @Override + public boolean setSelection(int start, int end) { + return false; + } + + public void setGLSurfaceView(Cocos2dxGLSurfaceView view) { + mView = view; + } + + private Cocos2dxGLSurfaceView mView; +} public class Cocos2dxGLSurfaceView extends GLSurfaceView { - private static final String TAG = Cocos2dxGLSurfaceView.class - .getCanonicalName(); + + static private Cocos2dxGLSurfaceView mainView; + + private static final String TAG = Cocos2dxGLSurfaceView.class.getCanonicalName(); private Cocos2dxRenderer mRenderer; private final boolean debug = false; + /////////////////////////////////////////////////////////////////////////// + // for initialize + /////////////////////////////////////////////////////////////////////////// public Cocos2dxGLSurfaceView(Context context) { super(context); initView(); @@ -27,6 +155,7 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView { mRenderer = new Cocos2dxRenderer(); setFocusableInTouchMode(true); setRenderer(mRenderer); + mainView = this; } public void onPause(){ @@ -51,6 +180,83 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView { }); } + /////////////////////////////////////////////////////////////////////////// + // for text input + /////////////////////////////////////////////////////////////////////////// + + 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, InputMethodManager.SHOW_IMPLICIT); + } + + 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); + } + + @Override + public boolean onCheckIsTextEditor() { + if (null == mainView) + { + return false; + } + return true; + } + + private Cocos2dxInputConnection ic; + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + if (onCheckIsTextEditor()) { + + outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT; + outAttrs.imeOptions = EditorInfo.IME_NULL; + outAttrs.initialSelStart = -1; + outAttrs.initialSelEnd = -1; + outAttrs.initialCapsMode = 0; + + if (null == ic) + { + ic = new Cocos2dxInputConnection(); + ic.setGLSurfaceView(this); + } + return ic; + } + return null; + } + + public void insertText(final String text) { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleInsertText(text); + } + }); + } + + public void deleteBackward() { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleDeleteBackward(); + } + }); + } + /////////////////////////////////////////////////////////////////////////// + // for touch event + /////////////////////////////////////////////////////////////////////////// + public boolean onTouchEvent(final MotionEvent event) { // these data are used in ACTION_MOVE and ACTION_CANCEL final int pointerNumber = event.getPointerCount(); diff --git a/tests/test.android/src/org/cocos2dx/lib/Cocos2dxRenderer.java b/tests/test.android/src/org/cocos2dx/lib/Cocos2dxRenderer.java index 06f389d65b..d56651c6f4 100644 --- a/tests/test.android/src/org/cocos2dx/lib/Cocos2dxRenderer.java +++ b/tests/test.android/src/org/cocos2dx/lib/Cocos2dxRenderer.java @@ -75,7 +75,6 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer { public static void setAnimationInterval(double interval){ animationInterval = (long)(interval * NANOSECONDSPERSECOND); } - private static native void nativeTouchesBegin(int id, float x, float y); private static native void nativeTouchesEnd(int id, float x, float y); private static native void nativeTouchesMove(int[] id, float[] x, float[] y); @@ -85,4 +84,19 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer { private static native void nativeInit(int w, int h); private static native void nativeOnPause(); private static native void nativeOnResume(); + + ///////////////////////////////////////////////////////////////////////////////// + // handle input method edit message + ///////////////////////////////////////////////////////////////////////////////// + + public void handleInsertText(final String text) { + nativeInsertText(text); + } + + public void handleDeleteBackward() { + nativeDeleteBackward(); + } + + private static native void nativeInsertText(String text); + private static native void nativeDeleteBackward(); } diff --git a/tests/test.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id b/tests/test.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id index 73f6a9f571..8e02741885 100644 --- a/tests/test.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/tests/test.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -248fcaeecce01b0f5a391117dfb33f5332030bdf \ No newline at end of file +85a9422443707c5ba69d66e2047740c1a865b91c \ No newline at end of file diff --git a/tests/test.win32/test.win32.vcproj b/tests/test.win32/test.win32.vcproj index 18a10da4ce..27f13aad47 100644 --- a/tests/test.win32/test.win32.vcproj +++ b/tests/test.win32/test.win32.vcproj @@ -935,6 +935,18 @@ > + + + + + + diff --git a/tests/tests/TextInputTest/TextInputTest.cpp b/tests/tests/TextInputTest/TextInputTest.cpp new file mode 100644 index 0000000000..3a79c033dd --- /dev/null +++ b/tests/tests/TextInputTest/TextInputTest.cpp @@ -0,0 +1,262 @@ +#include "TextInputTest.h" + +////////////////////////////////////////////////////////////////////////// +// local function +////////////////////////////////////////////////////////////////////////// + +enum +{ + kTextFieldTTFTest, + kTextInputTestsCount, +}; + +static int testIdx = -1; + +CCLayer* createTextInputTest(int nIndex) +{ + switch(nIndex) + { + case kTextFieldTTFTest: return new TextFieldTTFTest(); + } + + return NULL; +} + +CCLayer* restartTextInputTest() +{ + CCLayer* pContainerLayer = new TextInputTest; + pContainerLayer->autorelease(); + + CCLayer* pTestLayer = createTextInputTest(testIdx); + pTestLayer->autorelease(); + + pContainerLayer->addChild(pTestLayer); + + return pContainerLayer; +} + +CCLayer* nextTextInputTest() +{ + testIdx++; + testIdx = testIdx % kTextInputTestsCount; + + return restartTextInputTest(); +} + +CCLayer* backTextInputTest() +{ + testIdx--; + int total = kTextInputTestsCount; + if( testIdx < 0 ) + testIdx += total; + + return restartTextInputTest(); +} + +CCRect getRect(CCNode * pNode) +{ + CCRect rc; + rc.origin = pNode->getPosition(); + rc.size = pNode->getContentSize(); + rc.origin.x -= rc.size.width / 2; + rc.origin.y -= rc.size.height / 2; + return rc; +} + +////////////////////////////////////////////////////////////////////////// +// implement TextInputTest +////////////////////////////////////////////////////////////////////////// + +void TextInputTest::restartCallback(CCObject* pSender) +{ + CCScene* s = new TextInputTestScene(); + s->addChild(restartTextInputTest()); + + CCDirector::sharedDirector()->replaceScene(s); + s->release(); +} + +void TextInputTest::nextCallback(CCObject* pSender) +{ + CCScene* s = new TextInputTestScene(); + s->addChild( nextTextInputTest() ); + CCDirector::sharedDirector()->replaceScene(s); + s->release(); +} + +void TextInputTest::backCallback(CCObject* pSender) +{ + CCScene* s = new TextInputTestScene(); + s->addChild( backTextInputTest() ); + CCDirector::sharedDirector()->replaceScene(s); + s->release(); +} + +void TextInputTest::onEnter() +{ + CCLayer::onEnter(); + + CCSize s = CCDirector::sharedDirector()->getWinSize(); + + CCLabelTTF* label = CCLabelTTF::labelWithString(title().c_str(), "Arial", 32); + addChild(label); + label->setPosition(ccp(s.width/2, s.height-50)); + + std::string subTitle = subtitle(); + if(! subTitle.empty()) + { + CCLabelTTF* l = CCLabelTTF::labelWithString(subTitle.c_str(), "Thonburi", 16); + addChild(l, 1); + l->setPosition(ccp(s.width/2, s.height-80)); + } + + CCMenuItemImage *item1 = CCMenuItemImage::itemFromNormalImage("Images/b1.png", "Images/b2.png", this, menu_selector(TextInputTest::backCallback)); + CCMenuItemImage *item2 = CCMenuItemImage::itemFromNormalImage("Images/r1.png","Images/r2.png", this, menu_selector(TextInputTest::restartCallback) ); + CCMenuItemImage *item3 = CCMenuItemImage::itemFromNormalImage("Images/f1.png", "Images/f2.png", this, menu_selector(TextInputTest::nextCallback) ); + + CCMenu *menu = CCMenu::menuWithItems(item1, item2, item3, NULL); + menu->setPosition(CCPointZero); + item1->setPosition(ccp( s.width/2 - 100,30)); + item2->setPosition(ccp( s.width/2, 30)); + item3->setPosition(ccp( s.width/2 + 100,30)); + + addChild(menu, 1); +} + +std::string TextInputTest::title() +{ + return "text input test"; +} + +std::string TextInputTest::subtitle() +{ + return ""; +} + +////////////////////////////////////////////////////////////////////////// +// implement KeyboardNotificationLayer +////////////////////////////////////////////////////////////////////////// + +KeyboardNotificationLayer::KeyboardNotificationLayer() +: m_pTrackNode(0) +{ + setIsTouchEnabled(true); +} + +void KeyboardNotificationLayer::registerWithTouchDispatcher() +{ + CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, false); +} + +void KeyboardNotificationLayer::keyboardWillShow(CCIMEKeyboardNotificationInfo& info) +{ + if (! m_pTrackNode) + { + return; + } + + CCRect rectTracked = getRect(m_pTrackNode); + if (! CCRect::CCRectIntersectsRect(rectTracked, info.end)) + { + return; + } + + float adjustVert = CCRect::CCRectGetMaxY(info.end) - CCRect::CCRectGetMinY(rectTracked); + + CCArray * children = getChildren(); + CCNode * node = 0; + int count = children->count(); + CCPoint pos; + for (int i = 0; i < count; ++i) + { + node = (CCNode*)children->objectAtIndex(i); + pos = node->getPosition(); + pos.y += adjustVert; + node->setPosition(pos); + } +} + +////////////////////////////////////////////////////////////////////////// +// implement TextFieldTTFTest +////////////////////////////////////////////////////////////////////////// + +TextFieldTTFTest::TextFieldTTFTest() +: m_nSelected(-1) +{ + CCSize s = CCDirector::sharedDirector()->getWinSize(); + + m_pTextField[0] = CCTextFieldTTF::textFieldWithPlaceHolder("", + CCSizeMake(240, 28), + CCTextAlignmentCenter, + "Thonburi", + 24); + addChild(m_pTextField[0]); + m_pTextField[0]->setPosition(ccp(s.width/2, s.height/2 + 16)); + + m_pTextField[1] = CCTextFieldTTF::textFieldWithPlaceHolder("", + "Thonburi", + 24); + addChild(m_pTextField[1]); + m_pTextField[1]->setPosition(ccp(s.width/2, s.height/2 - 16)); +} + +std::string TextFieldTTFTest::subtitle() +{ + return "CCTextFieldTTF test"; +} + +bool TextFieldTTFTest::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) +{ + m_beginPos = pTouch->locationInView(pTouch->view()); + m_beginPos = CCDirector::sharedDirector()->convertToGL(m_beginPos); + return true; +} + +void TextFieldTTFTest::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) +{ + CCPoint endPos = pTouch->locationInView(pTouch->view()); + endPos = CCDirector::sharedDirector()->convertToGL(endPos); + + float delta = 5.0f; + if (::abs(endPos.x - m_beginPos.x) > delta + || ::abs(endPos.y - m_beginPos.y) > delta) + { + // not click + m_beginPos.x = m_beginPos.y = -1; + return; + } + + int index = 0; + for (; index < sizeof(m_pTextField) / sizeof(CCTextFieldTTF *); ++index) + { + if (CCRect::CCRectContainsPoint(getRect(m_pTextField[index]), convertTouchToNodeSpaceAR(pTouch))) + { + break; + } + } + + if (index < sizeof(m_pTextField) / sizeof(CCTextFieldTTF *)) + { + m_nSelected = index; + m_pTrackNode = m_pTextField[index]; + m_pTextField[index]->attachWithIME(); + } + else if (m_nSelected >= 0) + { + m_pTextField[m_nSelected]->detachWithIME(); + m_nSelected = -1; + m_pTrackNode = 0; + } +} + +////////////////////////////////////////////////////////////////////////// +// implement TextInputTestScene +////////////////////////////////////////////////////////////////////////// + +void TextInputTestScene::runThisTest() +{ + CCLayer* pLayer = nextTextInputTest(); + addChild(pLayer); + + CCDirector::sharedDirector()->replaceScene(this); +} diff --git a/tests/tests/TextInputTest/TextInputTest.h b/tests/tests/TextInputTest/TextInputTest.h new file mode 100644 index 0000000000..8e48aad1e7 --- /dev/null +++ b/tests/tests/TextInputTest/TextInputTest.h @@ -0,0 +1,51 @@ +#ifndef __TEXT_INPUT_TEST_H__ +#define __TEXT_INPUT_TEST_H__ + +#include "../testBasic.h" + +class TextInputTest : public CCLayer, public CCIMEDelegate +{ +public: + void restartCallback(CCObject* pSender); + void nextCallback(CCObject* pSender); + void backCallback(CCObject* pSender); + + virtual std::string title(); + virtual std::string subtitle(); + + virtual void onEnter(); +}; + +class KeyboardNotificationLayer : public CCLayer, public CCIMEDelegate +{ +public: + KeyboardNotificationLayer(); + + virtual void registerWithTouchDispatcher(); + virtual void keyboardWillShow(CCIMEKeyboardNotificationInfo& info); + +protected: + CCNode * m_pTrackNode; +}; + +class TextFieldTTFTest : public KeyboardNotificationLayer +{ + CCPoint m_beginPos; + CCTextFieldTTF * m_pTextField[2]; + int m_nSelected; +public: + TextFieldTTFTest(); + + virtual std::string subtitle(); + + virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); + virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); +}; + +class TextInputTestScene : public TestScene +{ +public: + virtual void runThisTest(); +}; + +#endif // __TEXT_INPUT_TEST_H__ \ No newline at end of file diff --git a/tests/tests/controller.cpp b/tests/tests/controller.cpp index badab6d757..329b1a059d 100644 --- a/tests/tests/controller.cpp +++ b/tests/tests/controller.cpp @@ -34,7 +34,7 @@ static TestScene* CreateTestScene(int nIdx) case TEST_COCOSNODE: pScene = new CocosNodeTestScene(); break; case TEST_TOUCHES: - CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationPortrait); + CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationLandscapeLeft); pScene = new PongScene(); break; case TEST_MENU: pScene = new MenuTestScene(); break; @@ -52,18 +52,20 @@ static TestScene* CreateTestScene(int nIdx) pScene = new IntervalTestScene(); break; case TEST_CHIPMUNK: #if (CC_TARGET_PLATFORM != CC_PLATFORM_AIRPLAY) - CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationPortrait); + CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationLandscapeLeft); pScene = new ChipmunkTestScene(); break; #else #ifdef AIRPLAYUSECHIPMUNK #if (AIRPLAYUSECHIPMUNK == 1) - CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationPortrait); + CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationLandscapeLeft); pScene = new ChipmunkTestScene(); break; #endif #endif #endif - case TEST_ATLAS: + case TEST_LABEL: pScene = new AtlasTestScene(); break; + case TEST_TEXT_INPUT: + pScene = new TextInputTestScene(); break; case TEST_SPRITE: pScene = new SpriteTestScene(); break; case TEST_SCHEDULER: @@ -102,7 +104,7 @@ static TestScene* CreateTestScene(int nIdx) TestController::TestController() : m_tBeginPos(CCPointZero) { - CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationLandscapeLeft); + CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationPortrait); // add close menu CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(s_pPathClose, s_pPathClose, this, menu_selector(TestController::closeCallback) ); diff --git a/tests/tests/tests.h b/tests/tests/tests.h index 459f063ce1..344ffc3774 100644 --- a/tests/tests/tests.h +++ b/tests/tests/tests.h @@ -21,6 +21,7 @@ #include "TileMapTest/TileMapTest.h" #include "IntervalTest/IntervalTest.h" #include "LabelTest/LabelTest.h" +#include "TextInputTest/TextInputTest.h" #include "SpriteTest/SpriteTest.h" #include "SchedulerTest/SchedulerTest.h" #include "RenderTextureTest/RenderTextureTest.h" @@ -67,7 +68,8 @@ enum TEST_TILE_MAP, TEST_INTERVAL, TEST_CHIPMUNK, - TEST_ATLAS, + TEST_LABEL, + TEST_TEXT_INPUT, TEST_SPRITE, TEST_SCHEDULER, TEST_RENDERTEXTURE, @@ -107,6 +109,7 @@ const std::string g_aTestNames[TESTS_COUNT] = { "IntervalTest", "ChipmunkTest", "LabelTest", + "TextInputTest", "SpriteTest", "SchdulerTest", "RenderTextureTest",