From 4b4de5afc353bf98b3746f6a064597b6734a4b7e Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 26 Sep 2012 20:14:37 -0700 Subject: [PATCH] Fixed bug 1573 - SDL does not support system clipboard on Android. Philipp Wiesemann 2012-08-18 14:09:47 PDT there is currently no way in SDL to interact with the system clipboard on Android. I attached a patch which tries to implement the three clipboard functions for Android. It does not add the CLIPBOARDUPDATE event because this seems to require Android API 11 or polling. --- src/core/android/SDL_android.cpp | 78 ++++++++++++++++++++++++ src/core/android/SDL_android.h | 5 ++ src/video/android/SDL_androidclipboard.c | 26 ++++++++ src/video/android/SDL_androidclipboard.h | 10 +++ src/video/android/SDL_androidvideo.c | 6 ++ 5 files changed, 125 insertions(+) create mode 100644 src/video/android/SDL_androidclipboard.c create mode 100644 src/video/android/SDL_androidclipboard.h diff --git a/src/core/android/SDL_android.cpp b/src/core/android/SDL_android.cpp index e5b574d0c..a97e075ca 100755 --- a/src/core/android/SDL_android.cpp +++ b/src/core/android/SDL_android.cpp @@ -735,6 +735,84 @@ extern "C" int Android_JNI_FileClose(SDL_RWops* ctx) return Android_JNI_FileClose(ctx, true); } +// returns a new global reference which needs to be released later +static jobject Android_JNI_GetSystemServiceObject(const char* name) +{ + LocalReferenceHolder refs; + JNIEnv* env = Android_JNI_GetEnv(); + if (!refs.init(env)) { + return NULL; + } + + jstring service = env->NewStringUTF(name); + + jmethodID mid; + + mid = env->GetStaticMethodID(mActivityClass, "getContext", "()Landroid/content/Context;"); + jobject context = env->CallStaticObjectMethod(mActivityClass, mid); + + mid = env->GetMethodID(mActivityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); + jobject manager = env->CallObjectMethod(context, mid, service); + + env->DeleteLocalRef(service); + + return manager ? env->NewGlobalRef(manager) : NULL; +} + +#define SETUP_CLIPBOARD(error) \ + LocalReferenceHolder refs; \ + JNIEnv* env = Android_JNI_GetEnv(); \ + if (!refs.init(env)) { \ + return error; \ + } \ + jobject clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \ + if (!clipboard) { \ + return error; \ + } + +extern "C" int Android_JNI_SetClipboardText(const char* text) +{ + SETUP_CLIPBOARD(-1) + + jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "setText", "(Ljava/lang/CharSequence;)V"); + jstring string = env->NewStringUTF(text); + env->CallVoidMethod(clipboard, mid, string); + env->DeleteGlobalRef(clipboard); + env->DeleteLocalRef(string); + return 0; +} + +extern "C" char* Android_JNI_GetClipboardText() +{ + SETUP_CLIPBOARD(SDL_strdup("")) + + jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "getText", "()Ljava/lang/CharSequence;"); + jobject sequence = env->CallObjectMethod(clipboard, mid); + env->DeleteGlobalRef(clipboard); + if (sequence) { + mid = env->GetMethodID(env->GetObjectClass(sequence), "toString", "()Ljava/lang/String;"); + jstring string = reinterpret_cast(env->CallObjectMethod(sequence, mid)); + const char* utf = env->GetStringUTFChars(string, 0); + if (utf) { + char* text = SDL_strdup(utf); + env->ReleaseStringUTFChars(string, utf); + return text; + } + } + return SDL_strdup(""); +} + +extern "C" SDL_bool Android_JNI_HasClipboardText() +{ + SETUP_CLIPBOARD(SDL_FALSE) + + jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "hasText", "()Z"); + jboolean has = env->CallBooleanMethod(clipboard, mid); + env->DeleteGlobalRef(clipboard); + return has ? SDL_TRUE : SDL_FALSE; +} + + // returns 0 on success or -1 on error (others undefined then) // returns truthy or falsy value in plugged, charged and battery // returns the value in seconds and percent or -1 if not available diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 6d0939359..e87bddc67 100755 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -47,6 +47,11 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t ma size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num); int Android_JNI_FileClose(SDL_RWops* ctx); +/* Clipboard support */ +int Android_JNI_SetClipboardText(const char* text); +char* Android_JNI_GetClipboardText(); +SDL_bool Android_JNI_HasClipboardText(); + /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); diff --git a/src/video/android/SDL_androidclipboard.c b/src/video/android/SDL_androidclipboard.c new file mode 100644 index 000000000..031c90f8d --- /dev/null +++ b/src/video/android/SDL_androidclipboard.c @@ -0,0 +1,26 @@ +#include "SDL_config.h" + +#if SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidvideo.h" + +#include "../../core/android/SDL_android.h" + +int +Android_SetClipboardText(_THIS, const char *text) +{ + return Android_JNI_SetClipboardText(text); +} + +char * +Android_GetClipboardText(_THIS) +{ + return Android_JNI_GetClipboardText(); +} + +SDL_bool Android_HasClipboardText(_THIS) +{ + return Android_JNI_HasClipboardText(); +} + +#endif /* SDL_VIDEO_DRIVER_ANDROID */ diff --git a/src/video/android/SDL_androidclipboard.h b/src/video/android/SDL_androidclipboard.h new file mode 100644 index 000000000..d1eb6632c --- /dev/null +++ b/src/video/android/SDL_androidclipboard.h @@ -0,0 +1,10 @@ +#include "SDL_config.h" + +#ifndef _SDL_androidclipboard_h +#define _SDL_androidclipboard_h + +extern int Android_SetClipboardText(_THIS, const char *text); +extern char *Android_GetClipboardText(_THIS); +extern SDL_bool Android_HasClipboardText(_THIS); + +#endif /* _SDL_androidclipboard_h */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 8095e5b4f..05639ee63 100755 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -33,6 +33,7 @@ #include "../../events/SDL_windowevents_c.h" #include "SDL_androidvideo.h" +#include "SDL_androidclipboard.h" #include "SDL_androidevents.h" #include "SDL_androidkeyboard.h" #include "SDL_androidwindow.h" @@ -126,6 +127,11 @@ Android_CreateDevice(int devindex) device->SDL_ToggleScreenKeyboard = Android_ToggleScreenKeyboard; device->SDL_IsScreenKeyboardShown = Android_IsScreenKeyboardShown; + /* Clipboard */ + device->SetClipboardText = Android_SetClipboardText; + device->GetClipboardText = Android_GetClipboardText; + device->HasClipboardText = Android_HasClipboardText; + return device; }