diff --git a/FCLauncher/src/main/java/com/tungsten/fclauncher/keycodes/LwjglGlfwKeycode.java b/FCLauncher/src/main/java/com/tungsten/fclauncher/keycodes/LwjglGlfwKeycode.java new file mode 100644 index 00000000..1c6815e2 --- /dev/null +++ b/FCLauncher/src/main/java/com/tungsten/fclauncher/keycodes/LwjglGlfwKeycode.java @@ -0,0 +1,201 @@ +package com.tungsten.fclauncher.keycodes; +// Keycodes from https://github.com/glfw/glfw/blob/master/include/GLFW/glfw3.h + +/*-************************************************************************ + * GLFW 3.4 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2019 Camilla Löwy + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +@SuppressWarnings("unused") +public class LwjglGlfwKeycode { + /** The unknown key. */ + public static final short KEY_UNKNOWN = 0; // should be -1 + + /** Printable keys. */ + public static final short + KEY_SPACE = 32, + KEY_APOSTROPHE = 39, + KEY_COMMA = 44, + KEY_MINUS = 45, + KEY_PERIOD = 46, + KEY_SLASH = 47, + KEY_0 = 48, + KEY_1 = 49, + KEY_2 = 50, + KEY_3 = 51, + KEY_4 = 52, + KEY_5 = 53, + KEY_6 = 54, + KEY_7 = 55, + KEY_8 = 56, + KEY_9 = 57, + KEY_SEMICOLON = 59, + KEY_EQUAL = 61, + KEY_A = 65, + KEY_B = 66, + KEY_C = 67, + KEY_D = 68, + KEY_E = 69, + KEY_F = 70, + KEY_G = 71, + KEY_H = 72, + KEY_I = 73, + KEY_J = 74, + KEY_K = 75, + KEY_L = 76, + KEY_M = 77, + KEY_N = 78, + KEY_O = 79, + KEY_P = 80, + KEY_Q = 81, + KEY_R = 82, + KEY_S = 83, + KEY_T = 84, + KEY_U = 85, + KEY_V = 86, + KEY_W = 87, + KEY_X = 88, + KEY_Y = 89, + KEY_Z = 90, + KEY_LEFT_BRACKET = 91, + KEY_BACKSLASH = 92, + KEY_RIGHT_BRACKET = 93, + KEY_GRAVE_ACCENT = 96, + KEY_WORLD_1 = 161, + KEY_WORLD_2 = 162; + + /** Function keys. */ + public static final short + KEY_ESCAPE = 256, + KEY_ENTER = 257, + KEY_TAB = 258, + KEY_BACKSPACE = 259, + KEY_INSERT = 260, + KEY_DELETE = 261, + KEY_RIGHT = 262, + KEY_LEFT = 263, + KEY_DOWN = 264, + KEY_UP = 265, + KEY_PAGE_UP = 266, + KEY_PAGE_DOWN = 267, + KEY_HOME = 268, + KEY_END = 269, + KEY_CAPS_LOCK = 280, + KEY_SCROLL_LOCK = 281, + KEY_NUM_LOCK = 282, + KEY_PRINT_SCREEN = 283, + KEY_PAUSE = 284, + KEY_F1 = 290, + KEY_F2 = 291, + KEY_F3 = 292, + KEY_F4 = 293, + KEY_F5 = 294, + KEY_F6 = 295, + KEY_F7 = 296, + KEY_F8 = 297, + KEY_F9 = 298, + KEY_F10 = 299, + KEY_F11 = 300, + KEY_F12 = 301, + KEY_F13 = 302, + KEY_F14 = 303, + KEY_F15 = 304, + KEY_F16 = 305, + KEY_F17 = 306, + KEY_F18 = 307, + KEY_F19 = 308, + KEY_F20 = 309, + KEY_F21 = 310, + KEY_F22 = 311, + KEY_F23 = 312, + KEY_F24 = 313, + KEY_F25 = 314, + KEY_KP_0 = 320, + KEY_KP_1 = 321, + KEY_KP_2 = 322, + KEY_KP_3 = 323, + KEY_KP_4 = 324, + KEY_KP_5 = 325, + KEY_KP_6 = 326, + KEY_KP_7 = 327, + KEY_KP_8 = 328, + KEY_KP_9 = 329, + KEY_KP_DECIMAL = 330, + KEY_KP_DIVIDE = 331, + KEY_KP_MULTIPLY = 332, + KEY_KP_SUBTRACT = 333, + KEY_KP_ADD = 334, + KEY_KP_ENTER = 335, + KEY_KP_EQUAL = 336, + KEY_LEFT_SHIFT = 340, + KEY_LEFT_CONTROL = 341, + KEY_LEFT_ALT = 342, + KEY_LEFT_SUPER = 343, + KEY_RIGHT_SHIFT = 344, + KEY_RIGHT_CONTROL = 345, + KEY_RIGHT_ALT = 346, + KEY_RIGHT_SUPER = 347, + KEY_MENU = 348, + KEY_LAST = KEY_MENU; + + /** If this bit is set one or more Shift keys were held down. */ + public static final int GLFW_MOD_SHIFT = 0x1; + + /** If this bit is set one or more Control keys were held down. */ + public static final int GLFW_MOD_CONTROL = 0x2; + + /** If this bit is set one or more Alt keys were held down. */ + public static final int GLFW_MOD_ALT = 0x4; + + /** If this bit is set one or more Super keys were held down. */ + public static final int GLFW_MOD_SUPER = 0x8; + + /** If this bit is set the Caps Lock key is enabled and the LOCK_KEY_MODS input mode is set. */ + public static final int GLFW_MOD_CAPS_LOCK = 0x10; + + /** If this bit is set the Num Lock key is enabled and the LOCK_KEY_MODS input mode is set. */ + public static final int GLFW_MOD_NUM_LOCK = 0x20; + + + /** Mouse buttons. See mouse button input for how these are used. */ + public static final short + GLFW_MOUSE_BUTTON_1 = 0, + GLFW_MOUSE_BUTTON_2 = 1, + GLFW_MOUSE_BUTTON_3 = 2, + GLFW_MOUSE_BUTTON_4 = 3, + GLFW_MOUSE_BUTTON_5 = 4, + GLFW_MOUSE_BUTTON_6 = 5, + GLFW_MOUSE_BUTTON_7 = 6, + GLFW_MOUSE_BUTTON_8 = 7, + GLFW_MOUSE_BUTTON_LAST = GLFW_MOUSE_BUTTON_8, + GLFW_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1, + GLFW_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2, + GLFW_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3; + + public static final int + GLFW_VISIBLE = 0x20004, + GLFW_HOVERED = 0x2000B; +} \ No newline at end of file diff --git a/FCLauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/FCLauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java new file mode 100644 index 00000000..133dbfc9 --- /dev/null +++ b/FCLauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -0,0 +1,231 @@ +package org.lwjgl.glfw; + +import android.content.*; +import android.view.Choreographer; + +import androidx.annotation.Nullable; + +import com.tungsten.fclauncher.bridge.FCLBridge; +import com.tungsten.fclauncher.keycodes.LwjglGlfwKeycode; +import com.tungsten.fclauncher.utils.FCLPath; + +import java.util.function.Consumer; + +import dalvik.annotation.optimization.CriticalNative; + +public class CallbackBridge { + public static final Choreographer sChoreographer = Choreographer.getInstance(); + private static FCLBridge fclBridge = null; + private static boolean isGrabbing = false; + private static final Consumer grabListener = isGrabbing -> CallbackBridge.fclBridge.setCursorMode(isGrabbing ? FCLBridge.CursorDisabled : FCLBridge.CursorEnabled); + + public static final int CLIPBOARD_COPY = 2000; + public static final int CLIPBOARD_PASTE = 2001; + public static final int CLIPBOARD_OPEN = 2002; + + public static volatile int windowWidth, windowHeight; + public static volatile int physicalWidth, physicalHeight; + public static float mouseX, mouseY; + public volatile static boolean holdingAlt, holdingCapslock, holdingCtrl, + holdingNumlock, holdingShift; + + public static void putMouseEventWithCoords(int button, float x, float y) { + putMouseEventWithCoords(button, true, x, y); + sChoreographer.postFrameCallbackDelayed(l -> putMouseEventWithCoords(button, false, x, y), 33); + } + + public static void putMouseEventWithCoords(int button, boolean isDown, float x, float y /* , int dz, long nanos */) { + sendCursorPos(x, y); + sendMouseKeycode(button, CallbackBridge.getCurrentMods(), isDown); + } + + + public static void sendCursorPos(float x, float y) { + mouseX = x; + mouseY = y; + nativeSendCursorPos(mouseX, mouseY); + } + + public static void sendKeycode(int keycode, char keychar, int scancode, int modifiers, boolean isDown) { + // TODO CHECK: This may cause input issue, not receive input! + if (keycode != 0) { + nativeSendKey(keycode, scancode, isDown ? 1 : 0, modifiers); + } + if (isDown && keychar != '\u0000') { + nativeSendCharMods(keychar, modifiers); + nativeSendChar(keychar); + } + } + + public static void sendChar(char keychar, int modifiers) { + nativeSendCharMods(keychar, modifiers); + nativeSendChar(keychar); + } + + public static void sendKeyPress(int keyCode, int modifiers, boolean status) { + sendKeyPress(keyCode, 0, modifiers, status); + } + + public static void sendKeyPress(int keyCode, int scancode, int modifiers, boolean status) { + sendKeyPress(keyCode, '\u0000', scancode, modifiers, status); + } + + public static void sendKeyPress(int keyCode, char keyChar, int scancode, int modifiers, boolean status) { + CallbackBridge.sendKeycode(keyCode, keyChar, scancode, modifiers, status); + } + + public static void sendKeyPress(int keyCode) { + sendKeyPress(keyCode, CallbackBridge.getCurrentMods(), true); + sendKeyPress(keyCode, CallbackBridge.getCurrentMods(), false); + } + + public static void sendMouseButton(int button, boolean status) { + CallbackBridge.sendMouseKeycode(button, CallbackBridge.getCurrentMods(), status); + } + + public static void sendMouseKeycode(int button, int modifiers, boolean isDown) { + // if (isGrabbing()) DEBUG_STRING.append("MouseGrabStrace: " + android.util.Log.getStackTraceString(new Throwable()) + "\n"); + nativeSendMouseButton(button, isDown ? 1 : 0, modifiers); + } + + public static void sendMouseKeycode(int keycode) { + sendMouseKeycode(keycode, CallbackBridge.getCurrentMods(), true); + sendMouseKeycode(keycode, CallbackBridge.getCurrentMods(), false); + } + + public static void sendScroll(double xoffset, double yoffset) { + nativeSendScroll(xoffset, yoffset); + } + + public static void sendUpdateWindowSize(int w, int h) { + nativeSendScreenSize(w, h); + } + + public static boolean isGrabbing() { + // Avoid going through the JNI each time. + return isGrabbing; + } + + // Called from JRE side + @SuppressWarnings("unused") + public static @Nullable String accessAndroidClipboard(int type, String copy) { + ClipboardManager clipboard = (ClipboardManager) FCLPath.CONTEXT.getSystemService(Context.CLIPBOARD_SERVICE); + switch (type) { + case CLIPBOARD_COPY: + ClipData clip = ClipData.newPlainText("FCL Clipboard", copy); + clipboard.setPrimaryClip(clip); + return null; + + case CLIPBOARD_PASTE: + if (clipboard.hasPrimaryClip() && clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { + return clipboard.getPrimaryClip().getItemAt(0).getText().toString(); + } else { + return ""; + } + + case CLIPBOARD_OPEN: + FCLBridge.openLink(copy); + return null; + default: + return null; + } + } + + + public static int getCurrentMods() { + int currMods = 0; + if (holdingAlt) { + currMods |= LwjglGlfwKeycode.GLFW_MOD_ALT; + } + if (holdingCapslock) { + currMods |= LwjglGlfwKeycode.GLFW_MOD_CAPS_LOCK; + } + if (holdingCtrl) { + currMods |= LwjglGlfwKeycode.GLFW_MOD_CONTROL; + } + if (holdingNumlock) { + currMods |= LwjglGlfwKeycode.GLFW_MOD_NUM_LOCK; + } + if (holdingShift) { + currMods |= LwjglGlfwKeycode.GLFW_MOD_SHIFT; + } + return currMods; + } + + public static void setModifiers(int keyCode, boolean isDown) { + switch (keyCode) { + case LwjglGlfwKeycode.KEY_LEFT_SHIFT: + CallbackBridge.holdingShift = isDown; + break; + + case LwjglGlfwKeycode.KEY_LEFT_CONTROL: + CallbackBridge.holdingCtrl = isDown; + break; + + case LwjglGlfwKeycode.KEY_LEFT_ALT: + CallbackBridge.holdingAlt = isDown; + break; + + case LwjglGlfwKeycode.KEY_CAPS_LOCK: + CallbackBridge.holdingCapslock = isDown; + break; + + case LwjglGlfwKeycode.KEY_NUM_LOCK: + CallbackBridge.holdingNumlock = isDown; + break; + } + } + + public static void setFCLBridge(FCLBridge fclBridge) { + CallbackBridge.fclBridge = fclBridge; + } + + //Called from JRE side + @SuppressWarnings("unused") + private static void onGrabStateChanged(final boolean grabbing) { + isGrabbing = grabbing; + sChoreographer.postFrameCallbackDelayed((time) -> { + // If the grab re-changed, skip notify process + if (isGrabbing != grabbing) { + return; + } + synchronized (grabListener) { + grabListener.accept(isGrabbing); + } + }, 16); + + } + + @CriticalNative + public static native void nativeSetUseInputStackQueue(boolean useInputStackQueue); + + @CriticalNative + private static native boolean nativeSendChar(char codepoint); + + // GLFW: GLFWCharModsCallback deprecated, but is Minecraft still use? + @CriticalNative + private static native boolean nativeSendCharMods(char codepoint, int mods); + + @CriticalNative + private static native void nativeSendKey(int key, int scancode, int action, int mods); + + // private static native void nativeSendCursorEnter(int entered); + @CriticalNative + private static native void nativeSendCursorPos(float x, float y); + + @CriticalNative + private static native void nativeSendMouseButton(int button, int action, int mods); + + @CriticalNative + private static native void nativeSendScroll(double xoffset, double yoffset); + + @CriticalNative + private static native void nativeSendScreenSize(int width, int height); + + public static native void nativeSetWindowAttrib(int attrib, int value); + + static { + System.loadLibrary("pojavexec"); + } +} +