Implement AWT clipboard for copy-paste on 1.12.2 and lower

This commit is contained in:
artdeell 2023-07-12 16:23:05 +03:00
parent fcafb3ecfa
commit fe8fb7bd20
11 changed files with 143 additions and 29 deletions

View File

@ -1 +1 @@
HEllo PeopLE HEllo PeopLE1

View File

@ -8,9 +8,15 @@ public class AWTInputBridge {
public static void sendKey(char keychar, int keycode) { public static void sendKey(char keychar, int keycode) {
// TODO: Android -> AWT keycode mapping // TODO: Android -> AWT keycode mapping
nativeSendData(EVENT_TYPE_KEY, (int) keychar, keycode, 1, 0);
nativeSendData(EVENT_TYPE_KEY, (int) keychar, keycode, 0, 0); nativeSendData(EVENT_TYPE_KEY, (int) keychar, keycode, 0, 0);
} }
public static void sendKey(char keychar, int keycode, int state) {
// TODO: Android -> AWT keycode mapping
nativeSendData(EVENT_TYPE_KEY, (int) keychar, keycode, state, 0);
}
public static void sendChar(char keychar){ public static void sendChar(char keychar){
nativeSendData(EVENT_TYPE_CHAR, (int) keychar, 0, 0, 0); nativeSendData(EVENT_TYPE_CHAR, (int) keychar, 0, 0, 0);
} }
@ -33,6 +39,6 @@ public class AWTInputBridge {
} }
public static native void nativeSendData(int type, int i1, int i2, int i3, int i4); public static native void nativeSendData(int type, int i1, int i2, int i3, int i4);
@SuppressWarnings("unused") public static native void nativePutClipboard(String data); //TODO: feed the AWT clipboard public static native void nativeClipboardReceived(String data, String mimeTypeSub);
public static native void nativeMoveWindow(int xoff, int yoff); public static native void nativeMoveWindow(int xoff, int yoff);
} }

View File

@ -3,6 +3,7 @@ package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.MainActivity.fullyExit; import static net.kdt.pojavlaunch.MainActivity.fullyExit;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.ClipboardManager;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
@ -64,6 +65,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}catch (IOException e) { }catch (IOException e) {
Tools.showError(this, e, true); Tools.showError(this, e, true);
} }
MainActivity.GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mTouchCharInput = findViewById(R.id.awt_touch_char); mTouchCharInput = findViewById(R.id.awt_touch_char);
mTouchCharInput.setCharacterSender(new AwtCharSender()); mTouchCharInput.setCharacterSender(new AwtCharSender());
@ -328,6 +330,18 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
public void toggleKeyboard(View view) { public void toggleKeyboard(View view) {
mTouchCharInput.switchKeyboardState(); mTouchCharInput.switchKeyboardState();
} }
public void performCopy(View view) {
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_CONTROL, 1);
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_C);
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_CONTROL, 0);
}
public void performPaste(View view) {
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_CONTROL, 1);
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_V);
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_CONTROL, 0);
}
public int getJavaVersion(File modFile) { public int getJavaVersion(File modFile) {
try (ZipFile zipFile = new ZipFile(modFile)){ try (ZipFile zipFile = new ZipFile(modFile)){
ZipEntry manifest = zipFile.getEntry("META-INF/MANIFEST.MF"); ZipEntry manifest = zipFile.getEntry("META-INF/MANIFEST.MF");

View File

@ -11,6 +11,7 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -546,6 +547,38 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
}); });
} }
public static void querySystemClipboard() {
Tools.runOnUiThread(()->{
ClipData clipData = GLOBAL_CLIPBOARD.getPrimaryClip();
if(clipData == null) {
AWTInputBridge.nativeClipboardReceived(null, null);
return;
}
ClipData.Item firstClipItem = clipData.getItemAt(0);
//TODO: coerce to HTML if the clip item is styled
CharSequence clipItemText = firstClipItem.getText();
if(clipItemText == null) {
AWTInputBridge.nativeClipboardReceived(null, null);
return;
}
AWTInputBridge.nativeClipboardReceived(clipItemText.toString(), "plain");
});
}
public static void putClipboardData(String data, String mimeType) {
Tools.runOnUiThread(()-> {
ClipData clipData = null;
switch(mimeType) {
case "text/plain":
clipData = ClipData.newPlainText("AWT Paste", data);
break;
case "text/html":
clipData = ClipData.newHtmlText("AWT Paste", data, data);
}
if(clipData != null) GLOBAL_CLIPBOARD.setPrimaryClip(clipData);
});
}
@Override @Override
public void onClickedMenu() { public void onClickedMenu() {
drawerLayout.openDrawer(navDrawer); drawerLayout.openDrawer(navDrawer);

View File

@ -8,7 +8,6 @@ static JavaVM* dalvikJavaVMPtr;
static JavaVM* runtimeJavaVMPtr; static JavaVM* runtimeJavaVMPtr;
static JNIEnv* runtimeJNIEnvPtr_GRAPHICS; static JNIEnv* runtimeJNIEnvPtr_GRAPHICS;
static JNIEnv* runtimeJNIEnvPtr_INPUT; static JNIEnv* runtimeJNIEnvPtr_INPUT;
static JNIEnv* runtimeJNIEnvPtr_CLIPBOARD;
jclass class_CTCScreen; jclass class_CTCScreen;
jmethodID method_GetRGB; jmethodID method_GetRGB;
@ -18,13 +17,18 @@ jmethodID method_ReceiveInput;
jclass class_MainActivity; jclass class_MainActivity;
jmethodID method_OpenLink; jmethodID method_OpenLink;
jmethodID method_OpenPath; jmethodID method_OpenPath;
jmethodID method_QuerySystemClipboard;
jmethodID method_PutClipboardData;
jclass class_Frame; jclass class_Frame;
jclass class_Rectangle; jclass class_Rectangle;
jclass class_CTCClipboard = NULL;
jmethodID constructor_Rectangle; jmethodID constructor_Rectangle;
jmethodID method_GetFrames; jmethodID method_GetFrames;
jmethodID method_GetBounds; jmethodID method_GetBounds;
jmethodID method_SetBounds; jmethodID method_SetBounds;
jmethodID method_SystemClipboardDataReceived = NULL;
jfieldID field_x; jfieldID field_x;
jfieldID field_y; jfieldID field_y;
@ -37,6 +41,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
class_MainActivity = (*env)->NewGlobalRef(env,(*env)->FindClass(env, "net/kdt/pojavlaunch/MainActivity")); class_MainActivity = (*env)->NewGlobalRef(env,(*env)->FindClass(env, "net/kdt/pojavlaunch/MainActivity"));
method_OpenLink= (*env)->GetStaticMethodID(env, class_MainActivity, "openLink", "(Ljava/lang/String;)V"); method_OpenLink= (*env)->GetStaticMethodID(env, class_MainActivity, "openLink", "(Ljava/lang/String;)V");
method_OpenPath= (*env)->GetStaticMethodID(env, class_MainActivity, "openLink", "(Ljava/lang/String;)V"); method_OpenPath= (*env)->GetStaticMethodID(env, class_MainActivity, "openLink", "(Ljava/lang/String;)V");
method_QuerySystemClipboard = (*env)->GetStaticMethodID(env, class_MainActivity, "querySystemClipboard", "()V");
method_PutClipboardData = (*env)->GetStaticMethodID(env, class_MainActivity, "putClipboardData", "(Ljava/lang/String;Ljava/lang/String;)V");
} else if (dalvikJavaVMPtr != vm) { } else if (dalvikJavaVMPtr != vm) {
runtimeJavaVMPtr = vm; runtimeJavaVMPtr = vm;
} }
@ -118,33 +124,43 @@ JNIEXPORT jintArray JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_renderAWTScr
return androidRgbArray; return androidRgbArray;
} }
jobject clipboard = NULL; JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCClipboard_nQuerySystemClipboard(JNIEnv *env, jclass clazz) {
jclass clipboardClass; JNIEnv *dalvikEnv;char detachable = 0;
static jobject obtainClipboard(JNIEnv *env) { if((*dalvikJavaVMPtr)->GetEnv(dalvikJavaVMPtr, (void **) &dalvikEnv, JNI_VERSION_1_6) == JNI_EDETACHED) {
jclass toolkitClass = (*runtimeJNIEnvPtr_CLIPBOARD)->FindClass(runtimeJNIEnvPtr_CLIPBOARD,"java/awt/Toolkit"); (*dalvikJavaVMPtr)->AttachCurrentThread(dalvikJavaVMPtr, &dalvikEnv, NULL);
jobject toolkit = (*runtimeJNIEnvPtr_CLIPBOARD)->CallStaticObjectMethod(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass,(*runtimeJNIEnvPtr_CLIPBOARD)->GetStaticMethodID(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass,"getDefaultToolkit", "()Ljava/awt/Toolkit;")); detachable = 1;
clipboardClass = (*runtimeJNIEnvPtr_CLIPBOARD)->NewGlobalRef(runtimeJNIEnvPtr_CLIPBOARD,(*runtimeJNIEnvPtr_CLIPBOARD)->FindClass(runtimeJNIEnvPtr_CLIPBOARD,"java/awt/datatransfer/Clipboard")); }
clipboard = (*runtimeJNIEnvPtr_CLIPBOARD)->NewGlobalRef(runtimeJNIEnvPtr_CLIPBOARD,(*runtimeJNIEnvPtr_CLIPBOARD)->CallObjectMethod(runtimeJNIEnvPtr_CLIPBOARD,toolkit,(*runtimeJNIEnvPtr_CLIPBOARD)->GetMethodID(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass,"getSystemClipboard", "()Ljava/awt/datatransfer/Clipboard;"))); if(method_SystemClipboardDataReceived == NULL) {
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass); class_CTCClipboard = (*env)->NewGlobalRef(env, clazz);
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,toolkit); method_SystemClipboardDataReceived = (*env)->GetStaticMethodID(env, clazz, "systemClipboardDataReceived", "(Ljava/lang/String;Ljava/lang/String;)V");
}
(*dalvikEnv)->CallStaticVoidMethod(dalvikEnv, class_MainActivity, method_QuerySystemClipboard);
if(detachable) (*dalvikJavaVMPtr)->DetachCurrentThread(dalvikJavaVMPtr);
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCClipboard_nPutClipboardData(JNIEnv* env, jclass clazz, jstring clipboardData, jstring clipboardDataMime) {
Java_net_kdt_pojavlaunch_AWTInputBridge_nativePutClipboard(JNIEnv *env, jclass clazz, JNIEnv *dalvikEnv;char detachable = 0;
jstring data) { if((*dalvikJavaVMPtr)->GetEnv(dalvikJavaVMPtr, (void **) &dalvikEnv, JNI_VERSION_1_6) == JNI_EDETACHED) {
if (runtimeJNIEnvPtr_CLIPBOARD == NULL) { (*dalvikJavaVMPtr)->AttachCurrentThread(dalvikJavaVMPtr, &dalvikEnv, NULL);
if (runtimeJavaVMPtr != NULL) { detachable = 1;
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr_CLIPBOARD, NULL);
}else{
return;
}
} }
if(clipboard == NULL) obtainClipboard(runtimeJNIEnvPtr_CLIPBOARD);
jclass stringSelection = (*runtimeJNIEnvPtr_CLIPBOARD)->FindClass(runtimeJNIEnvPtr_CLIPBOARD,"java/awt/datatransfer/StringSelection"); const char* dataChars = (*env)->GetStringUTFChars(env, clipboardData, NULL);
jobject o_stringSelection = (*runtimeJNIEnvPtr_CLIPBOARD)->NewObject(runtimeJNIEnvPtr_CLIPBOARD,stringSelection,(*runtimeJNIEnvPtr_CLIPBOARD)->GetMethodID(runtimeJNIEnvPtr_CLIPBOARD,stringSelection,"<init>", "(Ljava/lang/String;)V"),NULL); const char* mimeChars = (*env)->GetStringUTFChars(env, clipboardDataMime, NULL);
(*runtimeJNIEnvPtr_CLIPBOARD)->CallVoidMethod(runtimeJNIEnvPtr_CLIPBOARD,clipboard,(*runtimeJNIEnvPtr_CLIPBOARD)->GetMethodID(env,clipboardClass,"setContents", "(Ljava/awt/datatransfer/Transferable;Ljava/awt/datatransfer/ClipboardOwner;)V"),o_stringSelection,NULL); (*dalvikEnv)->CallStaticVoidMethod(dalvikEnv, class_MainActivity, method_PutClipboardData,
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,stringSelection); (*dalvikEnv)->NewStringUTF(dalvikEnv, dataChars),
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,o_stringSelection); (*dalvikEnv)->NewStringUTF(dalvikEnv, mimeChars));
(*env)->ReleaseStringUTFChars(env, clipboardData, dataChars);
(*env)->ReleaseStringUTFChars(env, clipboardDataMime, mimeChars);
if(detachable) (*dalvikJavaVMPtr)->DetachCurrentThread(dalvikJavaVMPtr);
}
JNIEXPORT void JNICALL Java_com_github_caciocavallosilano_cacio_ctc_CTCClipboard_nQuerySystemClipboard(JNIEnv *env, jclass clazz) {
Java_net_java_openjdk_cacio_ctc_CTCClipboard_nQuerySystemClipboard(env, clazz);
}
JNIEXPORT void JNICALL Java_com_github_caciocavallosilano_cacio_ctc_CTCClipboard_nPutClipboardData(JNIEnv* env, jclass clazz, jstring clipboardData, jstring clipboardDataMime) {
Java_net_java_openjdk_cacio_ctc_CTCClipboard_nPutClipboardData(env, clazz, clipboardData, clipboardDataMime);
} }
JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCDesktopPeer_openFile(JNIEnv *env, jclass clazz, jstring filePath) { JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCDesktopPeer_openFile(JNIEnv *env, jclass clazz, jstring filePath) {
@ -171,6 +187,24 @@ JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCDesktopPeer_openUri(JN
if(detachable) (*dalvikJavaVMPtr)->DetachCurrentThread(dalvikJavaVMPtr); if(detachable) (*dalvikJavaVMPtr)->DetachCurrentThread(dalvikJavaVMPtr);
} }
JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_AWTInputBridge_nativeClipboardReceived(JNIEnv *env, jclass clazz, jstring clipboardData, jstring clipboardDataMime) {
if(method_SystemClipboardDataReceived == NULL || class_CTCClipboard == NULL) return;
if (runtimeJNIEnvPtr_INPUT == NULL) {
if (runtimeJavaVMPtr == NULL) {
return;
} else {
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr_INPUT, NULL);
}
}
const char* dataChars = clipboardData != NULL ? (*env)->GetStringUTFChars(env, clipboardData, NULL) : NULL;
const char* mimeChars = clipboardDataMime != NULL ? (*env)->GetStringUTFChars(env, clipboardDataMime, NULL) : NULL;
(*runtimeJNIEnvPtr_INPUT)->CallStaticVoidMethod(runtimeJNIEnvPtr_INPUT, class_CTCClipboard, method_SystemClipboardDataReceived,
clipboardData != NULL ? (*runtimeJNIEnvPtr_INPUT)->NewStringUTF(runtimeJNIEnvPtr_INPUT, dataChars) : NULL,
clipboardDataMime != NULL ? (*runtimeJNIEnvPtr_INPUT)->NewStringUTF(runtimeJNIEnvPtr_INPUT, mimeChars) : NULL);
if(dataChars != NULL) (*env)->ReleaseStringUTFChars(env, clipboardData, dataChars);
if(mimeChars != NULL) (*env)->ReleaseStringUTFChars(env, clipboardDataMime, mimeChars);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_net_kdt_pojavlaunch_AWTInputBridge_nativeMoveWindow(JNIEnv *env, jclass clazz, jint xoff, jint yoff) { Java_net_kdt_pojavlaunch_AWTInputBridge_nativeMoveWindow(JNIEnv *env, jclass clazz, jint xoff, jint yoff) {
if (runtimeJNIEnvPtr_INPUT == NULL) { if (runtimeJNIEnvPtr_INPUT == NULL) {

View File

@ -86,12 +86,39 @@
app:layout_constraintTop_toBottomOf="@+id/installmod_btn3" /> app:layout_constraintTop_toBottomOf="@+id/installmod_btn3" />
<Button <Button
android:id="@+id/button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:background="@drawable/control_button" android:background="@drawable/control_button"
android:onClick="toggleKeyboard"
android:text="Keyboard" android:text="Keyboard"
android:onClick="toggleKeyboard"/> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:background="@drawable/control_button"
android:onClick="performCopy"
android:text="Copy"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:background="@drawable/control_button"
android:onClick="performPaste"
android:text="Paste"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button3" />
<Button <Button
android:id="@+id/installmod_mouse_pri" android:id="@+id/installmod_mouse_pri"