From 99f734c61c50f0789f539510a5bc996fcf16d9d2 Mon Sep 17 00:00:00 2001 From: pelya Date: Thu, 24 Feb 2011 16:21:54 +0000 Subject: [PATCH] Added new API for toggling text input via Android EditText widget --- ChangeAppSettings.sh | 2 +- build.sh | 2 +- project/java/MainActivity.java | 5 +- project/java/Settings.java | 2 +- project/java/Video.java | 7 +- project/java/translations/values/strings.xml | 2 + .../ballfield/AndroidAppSettings.cfg | 2 +- .../fheroes2/AndroidAppSettings.cfg | 6 +- project/jni/application/src | 2 +- .../vice/vice-c64-2.3-pelyasdl.diff | 26 +++++++ .../jni/sdl-1.3/include/SDL_screenkeyboard.h | 9 ++- .../src/video/android/SDL_androidinput.c | 68 +++++++++++++++++-- .../src/video/android/SDL_androidvideo.c | 55 ++++++++++++--- .../src/video/android/SDL_androidvideo.h | 4 +- .../video/android/SDL_touchscreenkeyboard.c | 15 ++-- readme.txt | 3 +- todo.txt | 4 ++ 17 files changed, 174 insertions(+), 40 deletions(-) create mode 100644 project/jni/application/vice/vice-c64-2.3-pelyasdl.diff diff --git a/ChangeAppSettings.sh b/ChangeAppSettings.sh index 23815d8e9..148cd107f 100755 --- a/ChangeAppSettings.sh +++ b/ChangeAppSettings.sh @@ -579,7 +579,7 @@ done cd ../../.. echo Cleaning up dependencies -rm -rf project/libs/* +rm -rf project/libs/* project/gen for OUT in obj; do rm -rf project/$OUT/local/*/objs/sdl_main/* project/$OUT/local/*/libsdl_main.so rm -rf project/$OUT/local/*/libsdl-*.so diff --git a/build.sh b/build.sh index abad2da29..a91952aaf 100755 --- a/build.sh +++ b/build.sh @@ -32,6 +32,6 @@ cd project && env PATH=$NDKBUILDPATH nice -n19 ndk-build -j4 V=1 && \ cp jni/application/src/libapplication.so libs/armeabi && \ `which ndk-build | sed 's@/ndk-build@@'`/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$MYARCH/bin/arm-linux-androideabi-strip --strip-unneeded libs/armeabi/libapplication.so \ || true ; } && \ - ant `test -n "$1" && echo release || echo debug` && \ + ant debug && \ test -z "$1" && cd bin && adb install -r DemoActivity-debug.apk diff --git a/project/java/MainActivity.java b/project/java/MainActivity.java index d40e98ac6..812e396cc 100644 --- a/project/java/MainActivity.java +++ b/project/java/MainActivity.java @@ -242,6 +242,7 @@ public class MainActivity extends Activity { DemoRenderer.nativeTextInput( (int)text.charAt(i), (int)text.codePointAt(i) ); } } + DemoRenderer.nativeTextInputFinished(); _videoLayout.removeView(_screenKeyboard); _screenKeyboard = null; mGLView.setFocusableInTouchMode(true); @@ -249,7 +250,7 @@ public class MainActivity extends Activity { mGLView.requestFocus(); }; - public void showScreenKeyboard() + public void showScreenKeyboard(final String oldText) { if(_screenKeyboard != null) return; @@ -283,6 +284,8 @@ public class MainActivity extends Activity { }; _screenKeyboard = new EditText(this); _screenKeyboard.setOnKeyListener(new myKeyListener(this)); + _screenKeyboard.setHint(R.string.text_edit_click_here); + _screenKeyboard.setText(oldText); _videoLayout.addView(_screenKeyboard); _screenKeyboard.setFocusableInTouchMode(true); _screenKeyboard.setFocusable(true); diff --git a/project/java/Settings.java b/project/java/Settings.java index 0137d9fea..b73ce77c6 100644 --- a/project/java/Settings.java +++ b/project/java/Settings.java @@ -45,7 +45,7 @@ class Settings static boolean settingsLoaded = false; static boolean settingsChanged = false; - static final int SETTINGS_FILE_VERSION = 4; + static final int SETTINGS_FILE_VERSION = 5; static void Save(final MainActivity p) { diff --git a/project/java/Video.java b/project/java/Video.java index 72604b272..e188d1d62 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -253,18 +253,20 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer { return 1; } - public void showScreenKeyboard() // Called from native code + public void showScreenKeyboard(final String oldText) // Called from native code { class Callback implements Runnable { public MainActivity parent; + public String oldText; public void run() { - parent.showScreenKeyboard(); + parent.showScreenKeyboard(oldText); } } Callback cb = new Callback(); cb.parent = context; + cb.oldText = oldText; context.runOnUiThread(cb); } @@ -279,6 +281,7 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer { private native void nativeGlContextLost(); public native void nativeGlContextRecreated(); public static native void nativeTextInput( int ascii, int unicode ); + public static native void nativeTextInputFinished(); private MainActivity context = null; private AccelerometerReader accelerometer = null; diff --git a/project/java/translations/values/strings.xml b/project/java/translations/values/strings.xml index c38f7cd1a..95e72752b 100644 --- a/project/java/translations/values/strings.xml +++ b/project/java/translations/values/strings.xml @@ -143,4 +143,6 @@ Smooth the video Separate thread for video, will increase FPS on some devices + Tap to start typing, press Back when done + diff --git a/project/jni/application/ballfield/AndroidAppSettings.cfg b/project/jni/application/ballfield/AndroidAppSettings.cfg index 3c4c88aeb..c1512e7a9 100644 --- a/project/jni/application/ballfield/AndroidAppSettings.cfg +++ b/project/jni/application/ballfield/AndroidAppSettings.cfg @@ -2,7 +2,7 @@ AppSettingVersion=17 LibSdlVersion=1.2 AppName="Ballfield" -AppFullName=net.olofson.ballfield +AppFullName=net.olofson.ballfield.v426 ScreenOrientation=h InhibitSuspend=n AppDataDownloadUrl="Game data is 1 Mb|ballfield.zip" diff --git a/project/jni/application/fheroes2/AndroidAppSettings.cfg b/project/jni/application/fheroes2/AndroidAppSettings.cfg index aef695512..55578e43c 100644 --- a/project/jni/application/fheroes2/AndroidAppSettings.cfg +++ b/project/jni/application/fheroes2/AndroidAppSettings.cfg @@ -13,7 +13,7 @@ SwVideoMode=y AppUsesMouse=y AppNeedsTwoButtonMouse=y AppNeedsArrowKeys=n -AppNeedsTextInput=y +AppNeedsTextInput=n AppUsesJoystick=n AppHandlesJoystickSensitivity=n AppUsesMultitouch=n @@ -23,8 +23,8 @@ AppTouchscreenKeyboardKeysAmount=0 AppTouchscreenKeyboardKeysAmountAutoFire=0 RedefinedKeysScreenKb="LCTRL M T H E C SPACE C S L" MultiABI=n -AppVersionCode=226512 -AppVersionName="2265.12" +AppVersionCode=229312 +AppVersionName="2293.12" CompiledLibraries="sdl_net sdl_mixer sdl_image sdl_ttf png intl" CustomBuildScript=n AppCflags='-finline-functions -O2 -DWITH_ZLIB -DWITH_MIXER -DWITH_XML -DWITH_IMAGE -DWITH_TTF -DWITH_AI=simple' diff --git a/project/jni/application/src b/project/jni/application/src index 104f796a6..59d41f41e 120000 --- a/project/jni/application/src +++ b/project/jni/application/src @@ -1 +1 @@ -ballfield \ No newline at end of file +fheroes2 \ No newline at end of file diff --git a/project/jni/application/vice/vice-c64-2.3-pelyasdl.diff b/project/jni/application/vice/vice-c64-2.3-pelyasdl.diff new file mode 100644 index 000000000..0d9016a4a --- /dev/null +++ b/project/jni/application/vice/vice-c64-2.3-pelyasdl.diff @@ -0,0 +1,26 @@ +diff -ru orig/vice-2.3/src/arch/sdl/uimenu.c vice-2.3/src/arch/sdl/uimenu.c +--- orig/vice-2.3/src/arch/sdl/uimenu.c 2011-02-19 11:33:41.000000000 -0500 ++++ vice-2.3/src/arch/sdl/uimenu.c 2011-02-23 09:56:42.000000000 -0500 +@@ -750,8 +750,9 @@ + if (vsid_mode && (sdl_vsid_state & SDL_VSID_ACTIVE)) { + sdl_vsid_close(); + } +- ++#ifndef ANDROID + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); ++#endif + sdl_menu_state = 1; + ui_check_mouse_cursor(); + } +@@ -762,8 +763,9 @@ + + sdl_menu_state = 0; + ui_check_mouse_cursor(); ++#ifndef ANDROID + SDL_EnableKeyRepeat(0, 0); +- ++#endif + /* Do not resume sound if in warp mode */ + resources_get_int("WarpMode", &warp_state); + if (warp_state == 0) { + diff --git a/project/jni/sdl-1.3/include/SDL_screenkeyboard.h b/project/jni/sdl-1.3/include/SDL_screenkeyboard.h index 83eefb7e6..eb7289c69 100644 --- a/project/jni/sdl-1.3/include/SDL_screenkeyboard.h +++ b/project/jni/sdl-1.3/include/SDL_screenkeyboard.h @@ -70,11 +70,14 @@ extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardShown(); extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardSize(); -/* Show Android on-screen keyboard, and pass entered text back to application as SDL keypress events, previousText may be NULL */ +/* Show Android on-screen keyboard, and pass entered text back to application as SDL keypress events, +previousText is UTF-8 encoded, it may be NULL, only 256 first bytes will be used, and this call will not block */ extern DECLSPEC int SDLCALL SDL_ANDROID_ToggleScreenKeyboardTextInput(const char * previousText); -/* Show Android on-screen keyboard, and pass entered text back to application in a buffer, previousText may be NULL */ -extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(const char * previousText, char * outText, int outTextSize); +/* Show Android on-screen keyboard, and pass entered text back to application in a buffer, +using buffer contents as previous text (UTF-8 encoded), the buffer may be of any size - +this call will block until user typed all text */ +extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(char * textBuf, int textBufSize); /* Whether user redefined on-screen keyboard layout via SDL menu, app should not enforce it's own layout in that case */ extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardRedefinedByUser(); diff --git a/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c b/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c index 4f486e9c9..3af624850 100644 --- a/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c +++ b/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c @@ -117,6 +117,38 @@ int oldMouseX = 0; int oldMouseY = 0; int oldMouseButtons = 0; +static int UnicodeToUtf8(int src, char * dest) +{ + int len = 0; + if ( src <= 0x007f) { + *dest++ = (char)src; + len = 1; + } else if (src <= 0x07ff) { + *dest++ = (char)0xc0 | (src >> 6); + *dest++ = (char)0x80 | (src & 0x003f); + len = 2; + } else if (src == 0xFEFF) { + // nop -- zap the BOM + } else if (src >= 0xD800 && src <= 0xDFFF) { + // surrogates not supported + } else if (src <= 0xffff) { + *dest++ = (char)0xe0 | (src >> 12); + *dest++ = (char)0x80 | ((src >> 6) & 0x003f); + *dest++ = (char)0x80 | (src & 0x003f); + len = 3; + } else if (src <= 0xffff) { + *dest++ = (char)0xf0 | (src >> 18); + *dest++ = (char)0x80 | ((src >> 12) & 0x3f); + *dest++ = (char)0x80 | ((src >> 6) & 0x3f); + *dest++ = (char)0x80 | (src & 0x3f); + len = 4; + } else { + // out of Unicode range + } + *dest = 0; + return len; +} + static inline int InsideRect(const SDL_Rect * r, int x, int y) { return ( x >= r->x && x <= r->x + r->w ) && ( y >= r->y && y <= r->y + r->h ); @@ -639,16 +671,40 @@ JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeKey) ( JNIEnv* env, jobject thiz, jint SDL_ANDROID_MainThreadPushKeyboardKey( action ? SDL_PRESSED : SDL_RELEASED, TranslateKey(key) ); } -JNIEXPORT void JNICALL -JAVA_EXPORT_NAME(DemoRenderer_nativeTextInput) ( JNIEnv* env, jobject thiz, jint ascii, jint unicode ) +static char * textInputBuffer = NULL; +int textInputBufferLen = 0; +int textInputBufferPos = 0; + +void SDL_ANDROID_TextInputInit(char * buffer, int len) { - SDL_ANDROID_MainThreadPushText(ascii, unicode); + textInputBuffer = buffer; + textInputBufferLen = len; } +JNIEXPORT void JNICALL +JAVA_EXPORT_NAME(DemoRenderer_nativeTextInput) ( JNIEnv* env, jobject thiz, jint ascii, jint unicode ) +{ + if( !textInputBuffer ) + SDL_ANDROID_MainThreadPushText(ascii, unicode); + else + { + if( textInputBufferPos < textInputBufferLen + 4 ) + { + textInputBufferPos += UnicodeToUtf8(unicode, textInputBuffer + textInputBufferPos); + } + } +} + +JNIEXPORT void JNICALL +JAVA_EXPORT_NAME(DemoRenderer_nativeTextInputFinished) ( JNIEnv* env, jobject thiz ) +{ + textInputBuffer = NULL; + SDL_ANDROID_TextInputFinished(); +} static void updateOrientation ( float accX, float accY, float accZ ); -JNIEXPORT void JNICALL +JNIEXPORT void JNICALL JAVA_EXPORT_NAME(AccelerometerReader_nativeAccelerometer) ( JNIEnv* env, jobject thiz, jfloat accPosX, jfloat accPosY, jfloat accPosZ ) { #if SDL_VERSION_ATLEAST(1,3,0) @@ -1531,10 +1587,8 @@ extern void SDL_ANDROID_MainThreadPushText( int ascii, int unicode ) #if SDL_VERSION_ATLEAST(1,3,0) - // TODO: convert to UTF-8 ev->type = SDL_TEXTINPUT; - ev->text.text[0] = ascii; - ev->text.text[1] = 0; + UnicodeToUtf8(unicode, ev->text.text); #else diff --git a/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.c b/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.c index b840d7fa5..986b6bb8b 100644 --- a/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.c +++ b/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.c @@ -63,6 +63,7 @@ static jmethodID JavaSwapBuffers = NULL; static jmethodID JavaShowScreenKeyboard = NULL; static int glContextLost = 0; static int showScreenKeyboardDeferred = 0; +static const char * showScreenKeyboardOldText = ""; int SDL_ANDROID_SmoothVideo = 0; int SDL_ANDROID_VideoMultithreaded = 0; @@ -117,7 +118,7 @@ int SDL_ANDROID_CallJavaSwapBuffers() if( showScreenKeyboardDeferred ) { showScreenKeyboardDeferred = 0; - (*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaShowScreenKeyboard ); + (*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaShowScreenKeyboard, (*JavaEnv)->NewStringUTF(JavaEnv, showScreenKeyboardOldText) ); } SDL_ANDROID_ProcessDeferredEvents(); return 1; @@ -210,13 +211,51 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeGlContextRecreated) ( JNIEnv* env, jobject #endif } -void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, int blocking) +volatile static textInputFinished = 0; +void SDL_ANDROID_TextInputFinished() { - showScreenKeyboardDeferred = 1; - // Move mouse by 1 pixel to force screen update - int x, y; - SDL_GetMouseState( &x, &y ); - SDL_ANDROID_MainThreadPushMouseMotion(x > 0 ? x-1 : 0, y); + textInputFinished = 1; +}; + +#if SDL_VERSION_ATLEAST(1,3,0) +#else +extern int SDL_Flip(SDL_Surface *screen); +extern SDL_Surface *SDL_GetVideoSurface(void); +#endif + +void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, char * outBuf, int outBufLen) +{ + if( !outBuf ) + { + showScreenKeyboardDeferred = 1; + showScreenKeyboardOldText = oldText; + // Move mouse by 1 pixel to force screen update + int x, y; + SDL_GetMouseState( &x, &y ); + SDL_ANDROID_MainThreadPushMouseMotion(x > 0 ? x-1 : 0, y); + } + else + { + textInputFinished = 0; + SDL_ANDROID_TextInputInit(outBuf, outBufLen); + + if( SDL_ANDROID_VideoMultithreaded ) + { +#if SDL_VERSION_ATLEAST(1,3,0) +#else + // Dirty hack: we may call (*JavaEnv)->CallVoidMethod(...) only from video thread + showScreenKeyboardDeferred = 1; + showScreenKeyboardOldText = oldText; + SDL_Flip(SDL_GetVideoSurface()); +#endif + } + else + (*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaShowScreenKeyboard, (*JavaEnv)->NewStringUTF(JavaEnv, oldText) ); + + while( !textInputFinished ) + SDL_Delay(100); + textInputFinished = 0; + } } JNIEXPORT void JNICALL @@ -227,7 +266,7 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeInitJavaCallbacks) ( JNIEnv* env, jobject t JavaRendererClass = (*JavaEnv)->GetObjectClass(JavaEnv, thiz); JavaSwapBuffers = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "swapBuffers", "()I"); - JavaShowScreenKeyboard = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "showScreenKeyboard", "()V"); + JavaShowScreenKeyboard = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "showScreenKeyboard", "(Ljava/lang/String;)V"); ANDROID_InitOSKeymap(); diff --git a/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.h b/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.h index 8b0182ef1..6b56091ef 100644 --- a/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.h +++ b/project/jni/sdl-1.3/src/video/android/SDL_androidvideo.h @@ -40,12 +40,14 @@ extern int SDL_ANDROID_TouchscreenCalibrationX; extern int SDL_ANDROID_TouchscreenCalibrationY; extern int SDL_ANDROID_SmoothVideo; extern int SDL_ANDROID_VideoMultithreaded; +extern void SDL_ANDROID_TextInputInit(char * buffer, int len); +extern void SDL_ANDROID_TextInputFinished(); extern SDL_Surface *SDL_CurrentVideoSurface; extern SDL_Rect SDL_ANDROID_ForceClearScreenRect; extern int SDL_ANDROID_ShowScreenUnderFinger; extern SDL_Rect SDL_ANDROID_ShowScreenUnderFingerRect, SDL_ANDROID_ShowScreenUnderFingerRectSrc; extern int SDL_ANDROID_CallJavaSwapBuffers(); -extern void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, int blocking); +extern void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, char * outBuf, int outBufLen); extern int SDL_ANDROID_drawTouchscreenKeyboard(); extern void SDL_ANDROID_VideoContextLost(); extern void SDL_ANDROID_VideoContextRecreated(); diff --git a/project/jni/sdl-1.3/src/video/android/SDL_touchscreenkeyboard.c b/project/jni/sdl-1.3/src/video/android/SDL_touchscreenkeyboard.c index d09ae8569..b49dc1a9e 100644 --- a/project/jni/sdl-1.3/src/video/android/SDL_touchscreenkeyboard.c +++ b/project/jni/sdl-1.3/src/video/android/SDL_touchscreenkeyboard.c @@ -788,19 +788,16 @@ int SDL_ANDROID_GetScreenKeyboardSize() int SDL_ANDROID_ToggleScreenKeyboardTextInput(const char * previousText) { - const char * textIn = previousText; - if( textIn == NULL ) - textIn = ""; - SDL_ANDROID_CallJavaShowScreenKeyboard(textIn, 0); + static char textIn[255]; + strncpy(textIn, previousText, sizeof(textIn)); + textIn[sizeof(textIn)-1] = 0; + SDL_ANDROID_CallJavaShowScreenKeyboard(textIn, NULL, 0); return 1; }; -int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(const char * previousText, char * outText, int outTextSize) +int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(char * textBuf, int textBufSize) { - const char * textIn = previousText; - if( textIn == NULL ) - textIn = ""; - SDL_ANDROID_CallJavaShowScreenKeyboard(textIn, 1); + SDL_ANDROID_CallJavaShowScreenKeyboard(textBuf, textBuf, textBufSize); return 1; }; diff --git a/readme.txt b/readme.txt index a49fe8d9c..a05096cdd 100644 --- a/readme.txt +++ b/readme.txt @@ -174,7 +174,8 @@ and that may be not desired for older phones with very little storage. The script app2sd.sh will re-package your .apk file in such a way that the shared libraries will not be extracted by Android OS but by application itself, and it will remove them from internal storage right after starting up, -so you still need that space free, but only temporarily. +so you still need that space free, but only temporarily. +However your application will start up slower. How to compile your own application using automake/configure scripts diff --git a/todo.txt b/todo.txt index d3bc02609..dcb561d42 100644 --- a/todo.txt +++ b/todo.txt @@ -11,4 +11,8 @@ Bugs to fix - Support of libjnigraphics (it will disable on-screen keyboard, only SW SDL screen surface supported) +- Update screen keyboard text input API + +- Floating on-screen joystick + And that's all, I won't be doing any more development or fix other bugs (see bugs.txt for details).