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) {
// TODO: Android -> AWT keycode mapping
nativeSendData(EVENT_TYPE_KEY, (int) keychar, keycode, 1, 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){
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);
@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);
}

View File

@ -3,6 +3,7 @@ package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.MainActivity.fullyExit;
import android.annotation.SuppressLint;
import android.content.ClipboardManager;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
@ -64,6 +65,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}catch (IOException e) {
Tools.showError(this, e, true);
}
MainActivity.GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mTouchCharInput = findViewById(R.id.awt_touch_char);
mTouchCharInput.setCharacterSender(new AwtCharSender());
@ -328,6 +330,18 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
public void toggleKeyboard(View view) {
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) {
try (ZipFile zipFile = new ZipFile(modFile)){
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.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
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
public void onClickedMenu() {
drawerLayout.openDrawer(navDrawer);

View File

@ -8,7 +8,6 @@ static JavaVM* dalvikJavaVMPtr;
static JavaVM* runtimeJavaVMPtr;
static JNIEnv* runtimeJNIEnvPtr_GRAPHICS;
static JNIEnv* runtimeJNIEnvPtr_INPUT;
static JNIEnv* runtimeJNIEnvPtr_CLIPBOARD;
jclass class_CTCScreen;
jmethodID method_GetRGB;
@ -18,13 +17,18 @@ jmethodID method_ReceiveInput;
jclass class_MainActivity;
jmethodID method_OpenLink;
jmethodID method_OpenPath;
jmethodID method_QuerySystemClipboard;
jmethodID method_PutClipboardData;
jclass class_Frame;
jclass class_Rectangle;
jclass class_CTCClipboard = NULL;
jmethodID constructor_Rectangle;
jmethodID method_GetFrames;
jmethodID method_GetBounds;
jmethodID method_SetBounds;
jmethodID method_SystemClipboardDataReceived = NULL;
jfieldID field_x;
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"));
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_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) {
runtimeJavaVMPtr = vm;
}
@ -118,33 +124,43 @@ JNIEXPORT jintArray JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_renderAWTScr
return androidRgbArray;
}
jobject clipboard = NULL;
jclass clipboardClass;
static jobject obtainClipboard(JNIEnv *env) {
jclass toolkitClass = (*runtimeJNIEnvPtr_CLIPBOARD)->FindClass(runtimeJNIEnvPtr_CLIPBOARD,"java/awt/Toolkit");
jobject toolkit = (*runtimeJNIEnvPtr_CLIPBOARD)->CallStaticObjectMethod(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass,(*runtimeJNIEnvPtr_CLIPBOARD)->GetStaticMethodID(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass,"getDefaultToolkit", "()Ljava/awt/Toolkit;"));
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;")));
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,toolkitClass);
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,toolkit);
JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCClipboard_nQuerySystemClipboard(JNIEnv *env, jclass clazz) {
JNIEnv *dalvikEnv;char detachable = 0;
if((*dalvikJavaVMPtr)->GetEnv(dalvikJavaVMPtr, (void **) &dalvikEnv, JNI_VERSION_1_6) == JNI_EDETACHED) {
(*dalvikJavaVMPtr)->AttachCurrentThread(dalvikJavaVMPtr, &dalvikEnv, NULL);
detachable = 1;
}
if(method_SystemClipboardDataReceived == NULL) {
class_CTCClipboard = (*env)->NewGlobalRef(env, clazz);
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
Java_net_kdt_pojavlaunch_AWTInputBridge_nativePutClipboard(JNIEnv *env, jclass clazz,
jstring data) {
if (runtimeJNIEnvPtr_CLIPBOARD == NULL) {
if (runtimeJavaVMPtr != NULL) {
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr_CLIPBOARD, NULL);
}else{
return;
}
JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCClipboard_nPutClipboardData(JNIEnv* env, jclass clazz, jstring clipboardData, jstring clipboardDataMime) {
JNIEnv *dalvikEnv;char detachable = 0;
if((*dalvikJavaVMPtr)->GetEnv(dalvikJavaVMPtr, (void **) &dalvikEnv, JNI_VERSION_1_6) == JNI_EDETACHED) {
(*dalvikJavaVMPtr)->AttachCurrentThread(dalvikJavaVMPtr, &dalvikEnv, NULL);
detachable = 1;
}
if(clipboard == NULL) obtainClipboard(runtimeJNIEnvPtr_CLIPBOARD);
jclass stringSelection = (*runtimeJNIEnvPtr_CLIPBOARD)->FindClass(runtimeJNIEnvPtr_CLIPBOARD,"java/awt/datatransfer/StringSelection");
jobject o_stringSelection = (*runtimeJNIEnvPtr_CLIPBOARD)->NewObject(runtimeJNIEnvPtr_CLIPBOARD,stringSelection,(*runtimeJNIEnvPtr_CLIPBOARD)->GetMethodID(runtimeJNIEnvPtr_CLIPBOARD,stringSelection,"<init>", "(Ljava/lang/String;)V"),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);
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,stringSelection);
(*runtimeJNIEnvPtr_CLIPBOARD)->DeleteLocalRef(runtimeJNIEnvPtr_CLIPBOARD,o_stringSelection);
const char* dataChars = (*env)->GetStringUTFChars(env, clipboardData, NULL);
const char* mimeChars = (*env)->GetStringUTFChars(env, clipboardDataMime, NULL);
(*dalvikEnv)->CallStaticVoidMethod(dalvikEnv, class_MainActivity, method_PutClipboardData,
(*dalvikEnv)->NewStringUTF(dalvikEnv, dataChars),
(*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) {
@ -171,6 +187,24 @@ JNIEXPORT void JNICALL Java_net_java_openjdk_cacio_ctc_CTCDesktopPeer_openUri(JN
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
Java_net_kdt_pojavlaunch_AWTInputBridge_nativeMoveWindow(JNIEnv *env, jclass clazz, jint xoff, jint yoff) {
if (runtimeJNIEnvPtr_INPUT == NULL) {

View File

@ -86,12 +86,39 @@
app:layout_constraintTop_toBottomOf="@+id/installmod_btn3" />
<Button
android:id="@+id/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="toggleKeyboard"
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
android:id="@+id/installmod_mouse_pri"