diff --git a/.gitignore b/.gitignore index 70814f3e0..ec7f8af78 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ /build /*/build app_pojavlauncher/src/main/assets/components/jre +local.properties +.idea/ +app_pojavlauncher/.cxx/ diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index 1bf6cd6a8..a8f847e90 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -116,14 +116,17 @@ dependencies { // implementation 'com.wu-man:android-bsf-api:3.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.preference:preference:1.1.1' - implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.appcompat:appcompat:1.3.0' implementation 'androidx.legacy:legacy-preference-v14:1.0.0' - implementation 'com.google.android.material:material:1.2.1' - implementation 'androidx.annotation:annotation:1.1.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.annotation:annotation:1.2.0' implementation 'androidx.browser:browser:1.3.0' implementation "androidx.constraintlayout:constraintlayout:2.0.4" + implementation 'com.rarepebble:colorpicker:3.0.1' + implementation 'com.github.duanhong169:checkerboarddrawable:1.0.2' + // implementation 'com.intuit.sdp:sdp-android:1.0.5' // implementation 'com.intuit.ssp:ssp-android:1.0.5' diff --git a/app_pojavlauncher/src/main/java/com/kdt/DefocusableScrollView.java b/app_pojavlauncher/src/main/java/com/kdt/DefocusableScrollView.java new file mode 100644 index 000000000..9bbde79b4 --- /dev/null +++ b/app_pojavlauncher/src/main/java/com/kdt/DefocusableScrollView.java @@ -0,0 +1,50 @@ +package com.kdt; + +import android.content.Context; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.widget.ScrollView; + +public class DefocusableScrollView extends ScrollView { + + /* + What is this class for ? + It allows to ignore the focusing from an item such an EditText. + Ignoring it will stop the scrollView from refocusing on the view + */ + + private boolean keepFocusing = false; + + + public DefocusableScrollView(Context context) { + super(context); + } + + public DefocusableScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DefocusableScrollView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public DefocusableScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public void setKeepFocusing(boolean shouldKeepFocusing){ + keepFocusing = shouldKeepFocusing; + } + + public boolean isKeepFocusing(){ + return keepFocusing; + } + + @Override + protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) { + if(!keepFocusing) return 0; + return super.computeScrollDeltaToGetChildRectOnScreen(rect); + } + + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java deleted file mode 100644 index a9599f3a2..000000000 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java +++ /dev/null @@ -1,222 +0,0 @@ -package net.kdt.pojavlaunch; - -import android.util.*; -import android.view.*; - -import java.net.CookieHandler; -import java.util.*; - -import net.kdt.pojavlaunch.prefs.LauncherPreferences; -import org.lwjgl.glfw.*; - -public class AndroidLWJGLKeycode { - // Fix double letters on MC 1.9 and above - public static boolean isBackspaceAfterChar = true; - public static final ArrayMap androidToLwjglMap; - public static String[] androidKeyNameArray; - - static { - // Mapping Android Keycodes to LWJGL Keycodes - androidToLwjglMap = new ArrayMap(); - - // 0-9 keys - androidToLwjglMap.put(KeyEvent.KEYCODE_0, LWJGLGLFWKeycode.GLFW_KEY_0); - androidToLwjglMap.put(KeyEvent.KEYCODE_1, LWJGLGLFWKeycode.GLFW_KEY_1); - androidToLwjglMap.put(KeyEvent.KEYCODE_2, LWJGLGLFWKeycode.GLFW_KEY_2); - androidToLwjglMap.put(KeyEvent.KEYCODE_3, LWJGLGLFWKeycode.GLFW_KEY_3); - androidToLwjglMap.put(KeyEvent.KEYCODE_4, LWJGLGLFWKeycode.GLFW_KEY_4); - androidToLwjglMap.put(KeyEvent.KEYCODE_5, LWJGLGLFWKeycode.GLFW_KEY_5); - androidToLwjglMap.put(KeyEvent.KEYCODE_6, LWJGLGLFWKeycode.GLFW_KEY_6); - androidToLwjglMap.put(KeyEvent.KEYCODE_7, LWJGLGLFWKeycode.GLFW_KEY_7); - androidToLwjglMap.put(KeyEvent.KEYCODE_8, LWJGLGLFWKeycode.GLFW_KEY_8); - androidToLwjglMap.put(KeyEvent.KEYCODE_9, LWJGLGLFWKeycode.GLFW_KEY_9); - - // A-Z keys - androidToLwjglMap.put(KeyEvent.KEYCODE_A, LWJGLGLFWKeycode.GLFW_KEY_A); - androidToLwjglMap.put(KeyEvent.KEYCODE_B, LWJGLGLFWKeycode.GLFW_KEY_B); - androidToLwjglMap.put(KeyEvent.KEYCODE_C, LWJGLGLFWKeycode.GLFW_KEY_C); - androidToLwjglMap.put(KeyEvent.KEYCODE_D, LWJGLGLFWKeycode.GLFW_KEY_D); - androidToLwjglMap.put(KeyEvent.KEYCODE_E, LWJGLGLFWKeycode.GLFW_KEY_E); - androidToLwjglMap.put(KeyEvent.KEYCODE_F, LWJGLGLFWKeycode.GLFW_KEY_F); - androidToLwjglMap.put(KeyEvent.KEYCODE_G, LWJGLGLFWKeycode.GLFW_KEY_G); - androidToLwjglMap.put(KeyEvent.KEYCODE_H, LWJGLGLFWKeycode.GLFW_KEY_H); - androidToLwjglMap.put(KeyEvent.KEYCODE_I, LWJGLGLFWKeycode.GLFW_KEY_I); - androidToLwjglMap.put(KeyEvent.KEYCODE_J, LWJGLGLFWKeycode.GLFW_KEY_J); - androidToLwjglMap.put(KeyEvent.KEYCODE_K, LWJGLGLFWKeycode.GLFW_KEY_K); - androidToLwjglMap.put(KeyEvent.KEYCODE_L, LWJGLGLFWKeycode.GLFW_KEY_L); - androidToLwjglMap.put(KeyEvent.KEYCODE_M, LWJGLGLFWKeycode.GLFW_KEY_M); - androidToLwjglMap.put(KeyEvent.KEYCODE_N, LWJGLGLFWKeycode.GLFW_KEY_N); - androidToLwjglMap.put(KeyEvent.KEYCODE_O, LWJGLGLFWKeycode.GLFW_KEY_O); - androidToLwjglMap.put(KeyEvent.KEYCODE_P, LWJGLGLFWKeycode.GLFW_KEY_P); - androidToLwjglMap.put(KeyEvent.KEYCODE_Q, LWJGLGLFWKeycode.GLFW_KEY_Q); - androidToLwjglMap.put(KeyEvent.KEYCODE_R, LWJGLGLFWKeycode.GLFW_KEY_R); - androidToLwjglMap.put(KeyEvent.KEYCODE_S, LWJGLGLFWKeycode.GLFW_KEY_S); - androidToLwjglMap.put(KeyEvent.KEYCODE_T, LWJGLGLFWKeycode.GLFW_KEY_T); - androidToLwjglMap.put(KeyEvent.KEYCODE_U, LWJGLGLFWKeycode.GLFW_KEY_U); - androidToLwjglMap.put(KeyEvent.KEYCODE_V, LWJGLGLFWKeycode.GLFW_KEY_V); - androidToLwjglMap.put(KeyEvent.KEYCODE_W, LWJGLGLFWKeycode.GLFW_KEY_W); - androidToLwjglMap.put(KeyEvent.KEYCODE_X, LWJGLGLFWKeycode.GLFW_KEY_X); - androidToLwjglMap.put(KeyEvent.KEYCODE_Y, LWJGLGLFWKeycode.GLFW_KEY_Y); - androidToLwjglMap.put(KeyEvent.KEYCODE_Z, LWJGLGLFWKeycode.GLFW_KEY_Z); - - // Alt keys - androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT); - androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_ALT); - - // Escape key - androidToLwjglMap.put(KeyEvent.KEYCODE_BACK, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE); - - androidToLwjglMap.put(KeyEvent.KEYCODE_BACKSLASH, LWJGLGLFWKeycode.GLFW_KEY_BACKSLASH); - androidToLwjglMap.put(KeyEvent.KEYCODE_BREAK, LWJGLGLFWKeycode.GLFW_KEY_PAUSE); - androidToLwjglMap.put(KeyEvent.KEYCODE_CAPS_LOCK, LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK); - androidToLwjglMap.put(KeyEvent.KEYCODE_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA); - - // Control keys - androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL); - androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_CONTROL); - - androidToLwjglMap.put(KeyEvent.KEYCODE_DEL, LWJGLGLFWKeycode.GLFW_KEY_BACKSPACE); // Backspace - - // Arrow keys - androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_DOWN, LWJGLGLFWKeycode.GLFW_KEY_DOWN); - androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT); - androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT); - androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_UP, LWJGLGLFWKeycode.GLFW_KEY_UP); - - androidToLwjglMap.put(KeyEvent.KEYCODE_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER); - androidToLwjglMap.put(KeyEvent.KEYCODE_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL); - androidToLwjglMap.put(KeyEvent.KEYCODE_ESCAPE, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE); - - // Fn keys - androidToLwjglMap.put(KeyEvent.KEYCODE_F1, LWJGLGLFWKeycode.GLFW_KEY_F1); - androidToLwjglMap.put(KeyEvent.KEYCODE_F2, LWJGLGLFWKeycode.GLFW_KEY_F2); - androidToLwjglMap.put(KeyEvent.KEYCODE_F3, LWJGLGLFWKeycode.GLFW_KEY_F3); - androidToLwjglMap.put(KeyEvent.KEYCODE_F4, LWJGLGLFWKeycode.GLFW_KEY_F4); - androidToLwjglMap.put(KeyEvent.KEYCODE_F5, LWJGLGLFWKeycode.GLFW_KEY_F5); - androidToLwjglMap.put(KeyEvent.KEYCODE_F6, LWJGLGLFWKeycode.GLFW_KEY_F6); - androidToLwjglMap.put(KeyEvent.KEYCODE_F7, LWJGLGLFWKeycode.GLFW_KEY_F7); - androidToLwjglMap.put(KeyEvent.KEYCODE_F8, LWJGLGLFWKeycode.GLFW_KEY_F8); - androidToLwjglMap.put(KeyEvent.KEYCODE_F9, LWJGLGLFWKeycode.GLFW_KEY_F9); - androidToLwjglMap.put(KeyEvent.KEYCODE_F10, LWJGLGLFWKeycode.GLFW_KEY_F10); - androidToLwjglMap.put(KeyEvent.KEYCODE_F11, LWJGLGLFWKeycode.GLFW_KEY_F11); - androidToLwjglMap.put(KeyEvent.KEYCODE_F12, LWJGLGLFWKeycode.GLFW_KEY_F12); - // FIXME GLFW Function key - // androidToLwjglMap.put(KeyEvent.KEYCODE_FUNCTION, LWJGLGLFWKeycode.GLFW_KEY_FUNCTION); - - androidToLwjglMap.put(KeyEvent.KEYCODE_GRAVE, LWJGLGLFWKeycode.GLFW_KEY_GRAVE_ACCENT); - androidToLwjglMap.put(KeyEvent.KEYCODE_HOME, LWJGLGLFWKeycode.GLFW_KEY_HOME); - androidToLwjglMap.put(KeyEvent.KEYCODE_INSERT, LWJGLGLFWKeycode.GLFW_KEY_INSERT); - androidToLwjglMap.put(KeyEvent.KEYCODE_KANA, LWJGLGLFWKeycode.GLFW_KEY_K); - androidToLwjglMap.put(KeyEvent.KEYCODE_LEFT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_LEFT_BRACKET); - androidToLwjglMap.put(KeyEvent.KEYCODE_MINUS, LWJGLGLFWKeycode.GLFW_KEY_MINUS); - - // Num keys - androidToLwjglMap.put(KeyEvent.KEYCODE_NUM_LOCK, LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_0, LWJGLGLFWKeycode.GLFW_KEY_0); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_1, LWJGLGLFWKeycode.GLFW_KEY_1); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_2, LWJGLGLFWKeycode.GLFW_KEY_2); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_3, LWJGLGLFWKeycode.GLFW_KEY_3); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_4, LWJGLGLFWKeycode.GLFW_KEY_4); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_5, LWJGLGLFWKeycode.GLFW_KEY_5); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_6, LWJGLGLFWKeycode.GLFW_KEY_6); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_7, LWJGLGLFWKeycode.GLFW_KEY_7); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_8, LWJGLGLFWKeycode.GLFW_KEY_8); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_9, LWJGLGLFWKeycode.GLFW_KEY_9); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ADD, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE, LWJGLGLFWKeycode.GLFW_KEY_KP_DIVIDE); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DOT, LWJGLGLFWKeycode.GLFW_KEY_PERIOD); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, LWJGLGLFWKeycode.GLFW_KEY_KP_MULTIPLY); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, LWJGLGLFWKeycode.GLFW_KEY_KP_SUBTRACT); - - // Page keys - androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_DOWN, LWJGLGLFWKeycode.GLFW_KEY_PAGE_DOWN); - androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_UP, LWJGLGLFWKeycode.GLFW_KEY_PAGE_UP); - - androidToLwjglMap.put(KeyEvent.KEYCODE_PERIOD, LWJGLGLFWKeycode.GLFW_KEY_PERIOD); - androidToLwjglMap.put(KeyEvent.KEYCODE_PLUS, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD); - // androidToLwjglMap.put(KeyEvent.KEYCODE_POWER, LWJGLGLFWKeycode.GLFW_KEY_POWER); - androidToLwjglMap.put(KeyEvent.KEYCODE_RIGHT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_BRACKET); - androidToLwjglMap.put(KeyEvent.KEYCODE_SEMICOLON, LWJGLGLFWKeycode.GLFW_KEY_SEMICOLON); - - // Shift keys - androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT); - androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_SHIFT); - - androidToLwjglMap.put(KeyEvent.KEYCODE_SLASH, LWJGLGLFWKeycode.GLFW_KEY_SLASH); - // androidToLwjglMap.put(KeyEvent.KEYCODE_SLEEP, LWJGLGLFWKeycode.GLFW_KEY_SLEEP); - androidToLwjglMap.put(KeyEvent.KEYCODE_SPACE, LWJGLGLFWKeycode.GLFW_KEY_SPACE); - // androidToLwjglMap.put(KeyEvent.KEYCODE_SYSRQ, LWJGLGLFWKeycode.GLFW_KEY_SYSRQ); - androidToLwjglMap.put(KeyEvent.KEYCODE_TAB, LWJGLGLFWKeycode.GLFW_KEY_TAB); - // androidToLwjglMap.put(KeyEvent.KEYCODE_YEN, LWJGLGLFWKeycode.GLFW_KEY_YEN); - - // androidToLwjglMap.put(KeyEvent.KEYCODE_BUTTON_1, LWJGLGLFWKeycode.G - androidToLwjglMap.put(KeyEvent.KEYCODE_AT,LWJGLGLFWKeycode.GLFW_KEY_2); - androidToLwjglMap.put(KeyEvent.KEYCODE_POUND,LWJGLGLFWKeycode.GLFW_KEY_3); - } - - public static String[] generateKeyName() { - if (androidKeyNameArray == null) { - List keyName = new ArrayList(); - for (Integer perKey : androidToLwjglMap.keySet()) { - keyName.add(KeyEvent.keyCodeToString(perKey.intValue()).replace("KEYCODE_", "")); - } - androidKeyNameArray = keyName.toArray(new String[0]); - } - return androidKeyNameArray; - } - - public static void execKey(KeyEvent keyEvent, int i, boolean isDown) { - CallbackBridge.holdingAlt = keyEvent.isAltPressed(); - CallbackBridge.holdingCapslock = keyEvent.isCapsLockOn(); - CallbackBridge.holdingCtrl = keyEvent.isCtrlPressed(); - CallbackBridge.holdingNumlock = keyEvent.isNumLockOn(); - CallbackBridge.holdingShift = keyEvent.isShiftPressed(); - - try { - System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel()); - if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && LauncherPreferences.PREF_BACK_TO_RIGHT_MOUSE) { - BaseMainActivity.sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, keyEvent.getAction() == KeyEvent.ACTION_DOWN); - } else { - if(keyEvent.getUnicodeChar() != 0) { - char key = (char)keyEvent.getUnicodeChar(); - BaseMainActivity.sendKeyPress( - androidToLwjglMap.get(keyEvent.getKeyCode()), - key, - 0, - CallbackBridge.getCurrentMods(), - keyEvent.getAction() == KeyEvent.ACTION_DOWN); - }else{ - BaseMainActivity.sendKeyPress( - androidToLwjglMap.get(keyEvent.getKeyCode()), - CallbackBridge.getCurrentMods(), - keyEvent.getAction()==KeyEvent.ACTION_DOWN); - } - } - } catch (Throwable th) { - th.printStackTrace(); - } - } - - public static void execKeyIndex(BaseMainActivity mainActivity, int index) { - mainActivity.sendKeyPress(getKeyByIndex(index)); - - } - - public static int getKeyByIndex(int index) { - return androidToLwjglMap.valueAt(index); - } - - public static int getIndexByLWJGLKey(int lwjglKey) { - for (int i = 0; i < androidToLwjglMap.size(); i++) { - int currKey = androidToLwjglMap.valueAt(i); - if (currKey == lwjglKey) { - return i; - } - } - - return 0; - } -} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java index 54330cfea..903179cd5 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java @@ -11,16 +11,17 @@ import android.view.View.*; import android.view.inputmethod.*; import android.widget.*; -import androidx.annotation.NonNull; import androidx.drawerlayout.widget.*; import com.google.android.material.navigation.*; import java.io.*; import java.lang.reflect.*; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; import java.util.*; import net.kdt.pojavlaunch.customcontrols.*; + import net.kdt.pojavlaunch.multirt.MultiRTUtils; + +import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad; + import net.kdt.pojavlaunch.prefs.*; import net.kdt.pojavlaunch.utils.*; import net.kdt.pojavlaunch.value.*; @@ -28,25 +29,31 @@ import org.lwjgl.glfw.*; public class BaseMainActivity extends LoggableActivity { public static volatile ClipboardManager GLOBAL_CLIPBOARD; - - public static final String initText = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "; + volatile public static boolean isInputStackCall; - private static int[] hotbarKeys = { + private static final int[] hotbarKeys = { LWJGLGLFWKeycode.GLFW_KEY_1, LWJGLGLFWKeycode.GLFW_KEY_2, LWJGLGLFWKeycode.GLFW_KEY_3, LWJGLGLFWKeycode.GLFW_KEY_4, LWJGLGLFWKeycode.GLFW_KEY_5, LWJGLGLFWKeycode.GLFW_KEY_6, LWJGLGLFWKeycode.GLFW_KEY_7, LWJGLGLFWKeycode.GLFW_KEY_8, LWJGLGLFWKeycode.GLFW_KEY_9}; + private Gamepad gamepad; + private boolean rightOverride = false; - private float scaleFactor = 1; - private int fingerStillThreshold = 8; - private int initialX, initialY; + private DisplayMetrics displayMetrics; + public float scaleFactor = 1; + public double sensitivityFactor; + private final int fingerStillThreshold = 8; + private float initialX, initialY; private int scrollInitialX, scrollInitialY; + private float prevX, prevY; + private int currentPointerID; + private boolean mIsResuming = false; private static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028; private static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029; private static boolean triggeredLeftMouseButton = false; - private Handler theHandler = new Handler() { + private final Handler theHandler = new Handler() { public void handleMessage(Message msg) { if (!LauncherPreferences.PREF_DISABLE_GESTURES) { switch (msg.what) { @@ -70,21 +77,16 @@ public class BaseMainActivity extends LoggableActivity { private MinecraftGLView minecraftGLView; private int guiScale; - private DisplayMetrics displayMetrics; + public boolean hiddenTextIgnoreUpdate = true; - public String hiddenTextContents = initText; private boolean isVirtualMouseEnabled; private LinearLayout touchPad; private ImageView mousePointer; - //private EditText hiddenEditor; - // private ViewGroup overlayView; private MinecraftAccount mProfile; private DrawerLayout drawerLayout; private NavigationView navDrawer; - - // protected CapturedEditText mKeyHandlerView; private LinearLayout contentLog; private TextView textLog; @@ -95,7 +97,6 @@ public class BaseMainActivity extends LoggableActivity { private TextView debugText; private NavigationView.OnNavigationItemSelectedListener gameActionListener; public NavigationView.OnNavigationItemSelectedListener ingameControlsEditorListener; - // private String mQueueText = new String(); protected volatile JMinecraftVersionList.Version mVersionInfo; @@ -104,19 +105,12 @@ public class BaseMainActivity extends LoggableActivity { private File logFile; private PrintStream logStream; private PerVersionConfig.VersionConfig config; - /* - private LinearLayout contentCanvas; - private AWTSurfaceView contentCanvasView; - */ - private boolean resuming; - private boolean lastEnabled = false; + private final boolean lastEnabled = false; private boolean lastGrab = false; - private boolean isExited = false; + private final boolean isExited = false; private boolean isLogAllow = false; - private volatile int mouse_x, mouse_y; - // private int navBarHeight = 40; - - // private static Collection rsaPkcs1List; + + public volatile float mouse_x, mouse_y; // @Override public void onCreate(Bundle savedInstanceState) { @@ -156,7 +150,8 @@ public class BaseMainActivity extends LoggableActivity { // Minecraft 1.13+ isInputStackCall = mVersionInfo.arguments != null; - this.displayMetrics = Tools.getDisplayMetrics(this); + displayMetrics = Tools.getDisplayMetrics(this); + sensitivityFactor = 1.4 * (1080f/ displayMetrics.heightPixels); CallbackBridge.windowWidth = (int) ((float)displayMetrics.widthPixels * scaleFactor); CallbackBridge.windowHeight = (int) ((float)displayMetrics.heightPixels * scaleFactor); System.out.println("WidthHeight: " + CallbackBridge.windowWidth + ":" + CallbackBridge.windowHeight); @@ -168,50 +163,35 @@ public class BaseMainActivity extends LoggableActivity { drawerLayout = findViewById(R.id.main_drawer_options); navDrawer = findViewById(R.id.main_navigation_view); - gameActionListener = new NavigationView.OnNavigationItemSelectedListener() { - @Override - public boolean onNavigationItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.nav_forceclose: dialogForceClose(BaseMainActivity.this); - break; - case R.id.nav_viewlog: openLogOutput(); - break; - case R.id.nav_debug: toggleDebug(); - break; - case R.id.nav_customkey: dialogSendCustomKey(); - break; - case R.id.nav_mousespd: adjustMouseSpeedLive(); - break; - case R.id.nav_customctrl: openCustomControls(); - break; - } - //Toast.makeText(MainActivity.this, menuItem.getTitle() + ":" + menuItem.getItemId(), Toast.LENGTH_SHORT).show(); - - drawerLayout.closeDrawers(); - return true; + gameActionListener = menuItem -> { + switch (menuItem.getItemId()) { + case R.id.nav_forceclose: dialogForceClose(BaseMainActivity.this); + break; + case R.id.nav_viewlog: openLogOutput(); + break; + case R.id.nav_debug: toggleDebug(); + break; + case R.id.nav_customkey: dialogSendCustomKey(); + break; + case R.id.nav_mousespd: adjustMouseSpeedLive(); + break; + case R.id.nav_customctrl: openCustomControls(); + break; } + + drawerLayout.closeDrawers(); + return true; }; - navDrawer.setNavigationItemSelectedListener( - gameActionListener); + navDrawer.setNavigationItemSelectedListener(gameActionListener); - // this.overlayView = (ViewGroup) findViewById(R.id.main_control_overlay); - - //this.hiddenEditor = findViewById(R.id.hiddenTextbox); - - // Mouse pointer part - //this.mouseToggleButton = findButton(R.id.control_togglemouse); this.touchPad = findViewById(R.id.main_touchpad); touchPad.setFocusable(false); this.mousePointer = findViewById(R.id.main_mouse_pointer); - this.mousePointer.post(new Runnable(){ - - @Override - public void run() { - ViewGroup.LayoutParams params = mousePointer.getLayoutParams(); - params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE); - params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE); - } + this.mousePointer.post(() -> { + ViewGroup.LayoutParams params = mousePointer.getLayoutParams(); + params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE); + params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE); }); this.contentLog = findViewById(R.id.content_log_layout); @@ -219,404 +199,241 @@ public class BaseMainActivity extends LoggableActivity { this.textLog = (TextView) contentScroll.getChildAt(0); this.toggleLog = findViewById(R.id.content_log_toggle_log); this.toggleLog.setChecked(false); - // this.textLogBehindGL = (TextView) findViewById(R.id.main_log_behind_GL); - // this.textLogBehindGL.setTypeface(Typeface.MONOSPACE); this.textLog.setTypeface(Typeface.MONOSPACE); - this.toggleLog.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener(){ - - @Override - public void onCheckedChanged(CompoundButton button, boolean isChecked) - { - isLogAllow = isChecked; - appendToLog(""); - } - }); + this.toggleLog.setOnCheckedChangeListener((button, isChecked) -> { + isLogAllow = isChecked; + appendToLog(""); + }); this.debugText = findViewById(R.id.content_text_debug); this.minecraftGLView = findViewById(R.id.main_game_render_view); - // toggleGui(null); this.drawerLayout.closeDrawers(); -/* - mKeyHandlerView = findViewById(R.id.main_key_handler); - mKeyHandlerView.setSingleLine(false); - mKeyHandlerView.clearFocus(); - - AndroidLWJGLKeycode.isBackspaceAfterChar = true; // mVersionInfo.minimumLauncherVersion >= 18; -*/ + placeMouseAt(CallbackBridge.physicalWidth / 2, CallbackBridge.physicalHeight / 2); - new Thread(new Runnable(){ - - //private boolean isCapturing = false; - @Override - public void run() - { - while (!isExited) { - if (lastGrab != CallbackBridge.isGrabbing()) - mousePointer.post(new Runnable(){ - - @Override - public void run() - { - if (!CallbackBridge.isGrabbing() && isVirtualMouseEnabled) { - touchPad.setVisibility(View.VISIBLE); - placeMouseAt(displayMetrics.widthPixels / 2, displayMetrics.heightPixels / 2); - } - - if (CallbackBridge.isGrabbing() && touchPad.getVisibility() != View.GONE) { - touchPad.setVisibility(View.GONE); - } - /* - if (isAndroid8OrHigher()) { - if (!CallbackBridge.isGrabbing() && isCapturing) { - minecraftGLView.releasePointerCapture(); - minecraftGLView.clearFocus(); - isCapturing = false; - } else if (CallbackBridge.isGrabbing() && !isCapturing) { - minecraftGLView.requestFocus(); - minecraftGLView.requestPointerCapture(); - isCapturing = true; - } - } - */ - lastGrab = CallbackBridge.isGrabbing(); - } - }); - - // try { - // Thread.sleep(100); - // } catch (Throwable th) {} + Thread virtualMouseGrabThread = new Thread(() -> { + while (!isExited) { + if (lastGrab != CallbackBridge.isGrabbing()) + mousePointer.post(() -> { + if (!CallbackBridge.isGrabbing() && isVirtualMouseEnabled) { + touchPad.setVisibility(View.VISIBLE); + placeMouseAt(displayMetrics.widthPixels / 2, displayMetrics.heightPixels / 2); } - } - }, "VirtualMouseGrabThread").start(); + if (CallbackBridge.isGrabbing() && touchPad.getVisibility() != View.GONE) { + touchPad.setVisibility(View.GONE); + } + + lastGrab = CallbackBridge.isGrabbing(); + }); + + } + }, "VirtualMouseGrabThread"); + virtualMouseGrabThread.setPriority(Thread.MIN_PRIORITY); + virtualMouseGrabThread.start(); if (isAndroid8OrHigher()) { touchPad.setDefaultFocusHighlightEnabled(false); } - touchPad.setOnTouchListener(new OnTouchListener(){ - private float prevX, prevY; - @Override - public boolean onTouch(View v, MotionEvent event) { - // MotionEvent reports input details from the touch screen - // and other input controls. In this case, you are only - // interested in events where the touch position changed. - // int index = event.getActionIndex(); - if(CallbackBridge.isGrabbing()) { - minecraftGLView.dispatchTouchEvent(MotionEvent.obtain(event)); - System.out.println("Transitioned event" + event.hashCode() + " to MinecraftGLView"); - return false; - } - int action = event.getActionMasked(); + touchPad.setOnTouchListener((v, event) -> { + // MotionEvent reports input details from the touch screen + // and other input controls. In this case, you are only + // interested in events where the touch position changed. + // int index = event.getActionIndex(); + if(CallbackBridge.isGrabbing()) { + minecraftGLView.dispatchTouchEvent(MotionEvent.obtain(event)); + System.out.println("Transitioned event" + event.hashCode() + " to MinecraftGLView"); + return false; + } + int action = event.getActionMasked(); - float x = event.getX(); - float y = event.getY(); - if(event.getHistorySize() > 0) { - prevX = event.getHistoricalX(0); - prevY = event.getHistoricalY(0); - }else{ + float x = event.getX(); + float y = event.getY(); + float mouseX = mousePointer.getX(); + float mouseY = mousePointer.getY(); + + if (gestureDetector.onTouchEvent(event)) { + mouse_x = (mouseX * scaleFactor); + mouse_y = (mouseY * scaleFactor); + CallbackBridge.sendCursorPos(mouse_x, mouse_y); + CallbackBridge.sendMouseKeycode(rightOverride ? LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT : LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT); + if (!rightOverride) CallbackBridge.mouseLeft = true; + + + } else { + switch (action) { + case MotionEvent.ACTION_UP: // 1 + case MotionEvent.ACTION_CANCEL: // 3 + if (!rightOverride) CallbackBridge.mouseLeft = false; + break; + + case MotionEvent.ACTION_POINTER_DOWN: // 5 + scrollInitialX = CallbackBridge.mouseX; + scrollInitialY = CallbackBridge.mouseY; + break; + + case MotionEvent.ACTION_DOWN: prevX = x; prevY = y; - } - float mouseX = mousePointer.getTranslationX(); - float mouseY = mousePointer.getTranslationY(); + currentPointerID = event.getPointerId(0); + break; - if (gestureDetector.onTouchEvent(event)) { - mouse_x = (int) (mouseX * scaleFactor); - mouse_y = (int) (mouseY * scaleFactor); - CallbackBridge.sendCursorPos((int) (mouseX * scaleFactor), (int) (mouseY *scaleFactor)); - CallbackBridge.sendMouseKeycode(rightOverride ? LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT : LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT); - if (!rightOverride) { - CallbackBridge.mouseLeft = true; + case MotionEvent.ACTION_MOVE: // 2 + + if (!CallbackBridge.isGrabbing() && event.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature + CallbackBridge.sendScroll( Tools.pxToDp(CallbackBridge.mouseX - scrollInitialX)/30, Tools.pxToDp(CallbackBridge.mouseY - scrollInitialY)/30); + scrollInitialX = CallbackBridge.mouseX; + scrollInitialY = CallbackBridge.mouseY; + } else { + if(currentPointerID == event.getPointerId(0)) { + mouseX = Math.max(0, Math.min(displayMetrics.widthPixels, mouseX + (x - prevX) * LauncherPreferences.PREF_MOUSESPEED)); + mouseY = Math.max(0, Math.min(displayMetrics.heightPixels, mouseY + (y - prevY) * LauncherPreferences.PREF_MOUSESPEED)); + mouse_x = (mouseX * scaleFactor); + mouse_y = (mouseY * scaleFactor); + placeMouseAt(mouseX, mouseY); + CallbackBridge.sendCursorPos(mouse_x, mouse_y); + }else currentPointerID = event.getPointerId(0); + + prevX = x; + prevY = y; } - - } else { - switch (action) { - case MotionEvent.ACTION_UP: // 1 - case MotionEvent.ACTION_CANCEL: // 3 - if (!rightOverride) { - CallbackBridge.mouseLeft = false; - } - break; - - case MotionEvent.ACTION_POINTER_DOWN: // 5 - scrollInitialX = CallbackBridge.mouseX; - scrollInitialY = CallbackBridge.mouseY; - break; - - case MotionEvent.ACTION_POINTER_UP: // 6 - break; - - case MotionEvent.ACTION_MOVE: // 2 - if (!CallbackBridge.isGrabbing() && event.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { - CallbackBridge.sendScroll(CallbackBridge.mouseX - scrollInitialX, CallbackBridge.mouseY - scrollInitialY); - scrollInitialX = CallbackBridge.mouseX; - scrollInitialY = CallbackBridge.mouseY; - } else { - mouseX = Math.max(0, Math.min(displayMetrics.widthPixels, mouseX + (x - prevX)*LauncherPreferences.PREF_MOUSESPEED)); - mouseY = Math.max(0, Math.min(displayMetrics.heightPixels, mouseY + (y - prevY)*LauncherPreferences.PREF_MOUSESPEED)); - mouse_x = (int) (mouseX * scaleFactor); - mouse_y = (int) (mouseY * scaleFactor); - placeMouseAt(mouseX, mouseY); - CallbackBridge.sendCursorPos((int) (mouseX * scaleFactor), (int) (mouseY *scaleFactor)); - /* - if (!CallbackBridge.isGrabbing()) { - CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, 0, isLeftMouseDown); - CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, 0, isRightMouseDown); - } - */ - } - break; - } - } - - debugText.setText(CallbackBridge.DEBUG_STRING.toString()); - CallbackBridge.DEBUG_STRING.setLength(0); - - return true; + break; } - }); + } + + debugText.setText(CallbackBridge.DEBUG_STRING.toString()); + CallbackBridge.DEBUG_STRING.setLength(0); + + return true; + }); - // System.loadLibrary("Regal"); minecraftGLView.setFocusable(true); - // minecraftGLView.setEGLContextClientVersion(2); glTouchListener = new OnTouchListener(){ private boolean isTouchInHotbar = false; - private int hotbarX, hotbarY; @Override - public boolean onTouch(View p1, MotionEvent e) - { + public boolean onTouch(View p1, MotionEvent e) { - { - int mptrIndex = -1; - for (int i = 0; i < e.getPointerCount(); i++) { - if (e.getToolType(i) == MotionEvent.TOOL_TYPE_MOUSE) { //if there's at least one mouse... - mptrIndex = i; //index it - } + //Looking for a mouse to handle, won't have an effect if no mouse exists. + for (int i = 0; i < e.getPointerCount(); i++) { + if (e.getToolType(i) == MotionEvent.TOOL_TYPE_MOUSE) { + + if(CallbackBridge.isGrabbing()) return false; + CallbackBridge.sendCursorPos( e.getX(i) * scaleFactor, + e.getY(i) * scaleFactor); + return true; //mouse event handled successfully } - if (mptrIndex != -1) { - if(CallbackBridge.isGrabbing()) { - return false; - } - //handle mouse events by just sending the coords of the new point in touch event - int x = (int) (e.getX(mptrIndex) * scaleFactor); - int y = (int) (e.getY(mptrIndex) * scaleFactor); - CallbackBridge.mouseX = x; - CallbackBridge.mouseY = y; - CallbackBridge.sendCursorPos(x, y); - return true; // event handled sucessfully - }//if index IS -1, continue handling as an usual touch event } // System.out.println("Pre touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked())); - /* int x = ((int) e.getX()) * scaleFactor; - int y = ((int) e.getY()) * scaleFactor;*/ - if(e.getHistorySize() > 0 && CallbackBridge.isGrabbing()) { - mouse_x += (int)(e.getX() - e.getHistoricalX(0)); - mouse_y += (int)(e.getY() - e.getHistoricalY(0)); - } + + //Getting scaled position from the event if(!CallbackBridge.isGrabbing()) { - mouse_x = (int) (e.getX() * scaleFactor); - mouse_y = (int) (e.getY() * scaleFactor); + mouse_x = (e.getX() * scaleFactor); + mouse_y = (e.getY() * scaleFactor); } - int hudKeyHandled = handleGuiBar((int)e.getX(), (int)e.getY()); - if (!CallbackBridge.isGrabbing() && gestureDetector.onTouchEvent(e)) { - if (hudKeyHandled != -1) { - sendKeyPress(hudKeyHandled); - } else { - CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, mouse_x, mouse_y); - if (!rightOverride) { - CallbackBridge.mouseLeft = true; - } - } - } else { - switch (e.getActionMasked()) { - case MotionEvent.ACTION_DOWN: // 0 - CallbackBridge.sendPrepareGrabInitialPos(); - - isTouchInHotbar = hudKeyHandled != -1; - if (isTouchInHotbar) { - sendKeyPress(hudKeyHandled, 0, true); - hotbarX = (int)e.getX(); - hotbarY = (int)e.getY(); - - theHandler.sendEmptyMessageDelayed(BaseMainActivity.MSG_DROP_ITEM_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); - } else { - CallbackBridge.mouseX = mouse_x; - CallbackBridge.mouseY = mouse_y; - CallbackBridge.sendCursorPos(mouse_x, mouse_y); - if (!rightOverride) { - CallbackBridge.mouseLeft = true; - } - - if (CallbackBridge.isGrabbing()) { - // It cause hold left mouse while moving camera - // CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y); - initialX = mouse_x; - initialY = mouse_y; - theHandler.sendEmptyMessageDelayed(BaseMainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); - } - } - break; - - case MotionEvent.ACTION_UP: // 1 - case MotionEvent.ACTION_CANCEL: // 3 - if (!isTouchInHotbar) { - CallbackBridge.mouseX = mouse_x; - CallbackBridge.mouseY = mouse_y; - - // -TODO uncomment after fix wrong trigger - // CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y); - CallbackBridge.sendCursorPos(mouse_x, mouse_y); - if (!rightOverride) { - CallbackBridge.mouseLeft = false; - } - } - - if (CallbackBridge.isGrabbing()) { - // System.out.println((String) ("[Math.abs(" + initialX + " - " + x + ") = " + Math.abs(initialX - x) + "] < " + fingerStillThreshold)); - // System.out.println((String) ("[Math.abs(" + initialY + " - " + y + ") = " + Math.abs(initialY - y) + "] < " + fingerStillThreshold)); - if (isTouchInHotbar && Math.abs(hotbarX - mouse_x) < fingerStillThreshold && Math.abs(hotbarY - mouse_y) < fingerStillThreshold) { - sendKeyPress(hudKeyHandled, 0, false); - } else if (!triggeredLeftMouseButton && Math.abs(initialX - mouse_x) < fingerStillThreshold && Math.abs(initialY - mouse_y) < fingerStillThreshold) { - if (!LauncherPreferences.PREF_DISABLE_GESTURES) { - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, true); - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, false); - } - } - if (!isTouchInHotbar) { - if (triggeredLeftMouseButton) { - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, false); - } - triggeredLeftMouseButton = false; - theHandler.removeMessages(BaseMainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); - } else { - sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q, 0, false); - theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK); - } - } - - break; - - case MotionEvent.ACTION_POINTER_DOWN: // 5 - scrollInitialX = CallbackBridge.mouseX; - scrollInitialY = CallbackBridge.mouseY; - break; - - case MotionEvent.ACTION_POINTER_UP: // 6 - break; - - case MotionEvent.ACTION_MOVE: - if (!CallbackBridge.isGrabbing() && e.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { - CallbackBridge.sendScroll(mouse_x - scrollInitialX, mouse_y - scrollInitialY); - scrollInitialX = mouse_x; - scrollInitialY = mouse_y; - } else if (!isTouchInHotbar) { - CallbackBridge.mouseX = mouse_x; - CallbackBridge.mouseY = mouse_y; - - CallbackBridge.sendCursorPos(mouse_x, mouse_y); - } - break; - } + int hudKeyHandled; + if (!CallbackBridge.isGrabbing() && gestureDetector.onTouchEvent(e)){ + CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (int)mouse_x, (int)mouse_y); + if (!rightOverride) CallbackBridge.mouseLeft = true; + return true; } - -/* - int x = ((int) e.getX()) * scaleFactor; - int y = (minecraftGLView.getHeight() - ((int) e.getY())) * scaleFactor; - int hudKeyHandled = handleGuiBar(x, y, e); - if (!CallbackBridge.isGrabbing() && gestureDetector.onTouchEvent(e)) { - if (hudKeyHandled != -1) { - sendKeyPress(hudKeyHandled); - } else { - CallbackBridge.sendMouseEvent( - x, CallbackBridge.windowHeight - y, - rightOverride ? LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT : LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT - ); - if (!rightOverride) { - CallbackBridge.mouseLeft = true; - } - } - } else { - switch (e.getActionMasked()) { - case MotionEvent.ACTION_DOWN: // 0 - case MotionEvent.ACTION_POINTER_DOWN: // 5 - isTouchInHotbar = hudKeyHandled != -1; - if (isTouchInHotbar) { - sendKeyPress(hudKeyHandled, 0, true); - hotbarX = x; - hotbarY = y; - theHandler.sendEmptyMessageDelayed(MainActivity.MSG_DROP_ITEM_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); - } else { - CallbackBridge.sendCursorPos(x, CallbackBridge.windowHeight - y); - - // if (!rightOverride) - // CallbackBridge.mouseLeft = true; - - + switch (e.getActionMasked()) { + case MotionEvent.ACTION_DOWN: // 0 + CallbackBridge.sendPrepareGrabInitialPos(); - if (CallbackBridge.isGrabbing()) { - CallbackBridge.sendMouseKeycode(rightOverride ? LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT : LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, 0, true); - initialX = x; - initialY = y; - theHandler.sendEmptyMessageDelayed(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); - } - } + currentPointerID = e.getPointerId(0); + CallbackBridge.sendCursorPos(mouse_x, mouse_y); + prevX = e.getX(); + prevY = e.getY(); + + + hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY()); + isTouchInHotbar = hudKeyHandled != -1; + if (isTouchInHotbar) { + sendKeyPress(hudKeyHandled); + + theHandler.sendEmptyMessageDelayed(BaseMainActivity.MSG_DROP_ITEM_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); + CallbackBridge.sendCursorPos(mouse_x, mouse_y); break; - case MotionEvent.ACTION_UP: // 1 - case MotionEvent.ACTION_CANCEL: // 3 - case MotionEvent.ACTION_POINTER_UP: // 6 - if (!isTouchInHotbar) { - CallbackBridge.sendCursorPos(x, CallbackBridge.windowHeight - y); + } - // TODO uncomment after fix wrong trigger - // CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y); - if (!rightOverride) { - // CallbackBridge.mouseLeft = false; - } - } + if (!rightOverride) CallbackBridge.mouseLeft = true; - if (CallbackBridge.isGrabbing()) { - // System.out.println((String) ("[Math.abs(" + initialX + " - " + x + ") = " + Math.abs(initialX - x) + "] < " + fingerStillThreshold)); - // System.out.println((String) ("[Math.abs(" + initialY + " - " + y + ") = " + Math.abs(initialY - y) + "] < " + fingerStillThreshold)); - if (isTouchInHotbar && Math.abs(hotbarX - x) < fingerStillThreshold && Math.abs(hotbarY - y) < fingerStillThreshold) { - sendKeyPress(hudKeyHandled, 0, false); - } else if (!triggeredLeftMouseButton && Math.abs(initialX - x) < fingerStillThreshold && Math.abs(initialY - y) < fingerStillThreshold) { + if (CallbackBridge.isGrabbing()) { + // It cause hold left mouse while moving camera + initialX = mouse_x; + initialY = mouse_y; + if(!isTouchInHotbar) theHandler.sendEmptyMessageDelayed(BaseMainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER); + } + break; + + case MotionEvent.ACTION_UP: // 1 + case MotionEvent.ACTION_CANCEL: // 3 + if (!isTouchInHotbar) { + // -TODO uncomment after fix wrong trigger + if (!rightOverride) CallbackBridge.mouseLeft = false; + } + + if (CallbackBridge.isGrabbing()) { + if (!triggeredLeftMouseButton && Math.abs(initialX - mouse_x) < fingerStillThreshold && Math.abs(initialY - mouse_y) < fingerStillThreshold) { + if (!LauncherPreferences.PREF_DISABLE_GESTURES) { sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, true); sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, false); } - if (!isTouchInHotbar) { - if (triggeredLeftMouseButton) { - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, false); - } - triggeredLeftMouseButton = false; - theHandler.removeMessages(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); - } else { - sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q, 0, false); - theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK); - } } - break; - - default: if (!isTouchInHotbar) { - CallbackBridge.sendCursorPos(x, CallbackBridge.windowHeight - y); + if (triggeredLeftMouseButton) sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, false); + + triggeredLeftMouseButton = false; + theHandler.removeMessages(BaseMainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); + } else { + sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q, 0, false); + theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK); } - break; - - } + } + + break; + + case MotionEvent.ACTION_POINTER_DOWN: // 5 + scrollInitialX = CallbackBridge.mouseX; + scrollInitialY = CallbackBridge.mouseY; + //Checking if we are pressing the hotbar to select the item + hudKeyHandled = handleGuiBar((int)e.getX(e.getPointerCount()-1), (int) e.getY(e.getPointerCount()-1)); + if(hudKeyHandled != -1) sendKeyPress(hudKeyHandled); + break; + + case MotionEvent.ACTION_MOVE: + if (!CallbackBridge.isGrabbing() && e.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature + CallbackBridge.sendScroll(Tools.pxToDp(mouse_x - scrollInitialX)/30 , Tools.pxToDp(mouse_y - scrollInitialY)/30); + scrollInitialX = (int)mouse_x; + scrollInitialY = (int)mouse_y; + } else if (!isTouchInHotbar) { + //Camera movement + if(CallbackBridge.isGrabbing()){ + int pointerIndex = e.findPointerIndex(currentPointerID); + if(pointerIndex == -1){ + currentPointerID = e.getPointerId(0); + }else{ + mouse_x += (e.getX(pointerIndex) - prevX) * sensitivityFactor; + mouse_y += (e.getY(pointerIndex) - prevY) * sensitivityFactor; + } + prevX = e.getX(); + prevY = e.getY(); + } + + CallbackBridge.sendCursorPos(mouse_x, mouse_y); + } + break; } - */ - + debugText.setText(CallbackBridge.DEBUG_STRING.toString()); CallbackBridge.DEBUG_STRING.setLength(0); return true; - // return !CallbackBridge.isGrabbing(); } }; @@ -627,23 +444,19 @@ public class BaseMainActivity extends LoggableActivity { private boolean debugErrored = false; private String getMoving(float pos, boolean xOrY) { - if (pos == 0) { - return "STOPPED"; - } else if (pos > 0) { - return xOrY ? "RIGHT" : "DOWN"; - } else { // if (pos3 < 0) { - return xOrY ? "LEFT" : "UP"; - } + if (pos == 0) return "STOPPED"; + if (pos > 0) return xOrY ? "RIGHT" : "DOWN"; + return xOrY ? "LEFT" : "UP"; } @Override public boolean onCapturedPointer (View view, MotionEvent e) { if(e.getHistorySize() > 0) { - mouse_x += (int)(e.getX()*scaleFactor); - mouse_y += (int)(e.getY()*scaleFactor); + mouse_x += (e.getX()*scaleFactor); + mouse_y += (e.getY()*scaleFactor); } - CallbackBridge.mouseX = mouse_x; - CallbackBridge.mouseY = mouse_y; + CallbackBridge.mouseX = (int) mouse_x; + CallbackBridge.mouseY = (int) mouse_y; if(!CallbackBridge.isGrabbing()){ view.releasePointerCapture(); } @@ -652,21 +465,21 @@ public class BaseMainActivity extends LoggableActivity { StringBuilder builder = new StringBuilder(); try { builder.append("PointerCapture debug\n"); - builder.append("MotionEvent=" + e.getActionMasked() + "\n"); - builder.append("PressingBtn=" + MotionEvent.class.getDeclaredMethod("buttonStateToString").invoke(null, e.getButtonState()) + "\n\n"); + builder.append("MotionEvent=").append(e.getActionMasked()).append("\n"); + builder.append("PressingBtn=").append(MotionEvent.class.getDeclaredMethod("buttonStateToString").invoke(null, e.getButtonState())).append("\n\n"); - builder.append("PointerX=" + e.getX() + "\n"); - builder.append("PointerY=" + e.getY() + "\n"); - builder.append("RawX=" + e.getRawX() + "\n"); - builder.append("RawY=" + e.getRawY() + "\n\n"); + builder.append("PointerX=").append(e.getX()).append("\n"); + builder.append("PointerY=").append(e.getY()).append("\n"); + builder.append("RawX=").append(e.getRawX()).append("\n"); + builder.append("RawY=").append(e.getRawY()).append("\n\n"); - builder.append("XPos=" + mouse_x + "\n"); - builder.append("YPos=" + mouse_y + "\n\n"); - builder.append("MovingX=" + getMoving(e.getX(), true) + "\n"); - builder.append("MovingY=" + getMoving(e.getY(), false) + "\n"); + builder.append("XPos=").append(mouse_x).append("\n"); + builder.append("YPos=").append(mouse_y).append("\n\n"); + builder.append("MovingX=").append(getMoving(e.getX(), true)).append("\n"); + builder.append("MovingY=").append(getMoving(e.getY(), false)).append("\n"); } catch (Throwable th) { debugErrored = true; - builder.append("Error getting debug. The debug will be stopped!\n" + Log.getStackTraceString(th)); + builder.append("Error getting debug. The debug will be stopped!\n").append(Log.getStackTraceString(th)); } finally { debugText.setText(builder.toString()); builder.setLength(0); @@ -714,18 +527,14 @@ public class BaseMainActivity extends LoggableActivity { JREUtils.setupBridgeWindow(new Surface(texture)); - new Thread(new Runnable(){ - - @Override - public void run() { - try { - Thread.sleep(200); - runCraft(); - } catch (Throwable e) { - Tools.showError(BaseMainActivity.this, e, true); - } - } - }, "JVM Main thread").start(); + new Thread(() -> { + try { + Thread.sleep(200); + runCraft(); + } catch (Throwable e) { + Tools.showError(BaseMainActivity.this, e, true); + } + }, "JVM Main thread").start(); } } @@ -752,123 +561,94 @@ public class BaseMainActivity extends LoggableActivity { } } - /* - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - switch (event.getAction()) { - case KeyEvent.ACTION_DOWN: - AndroidLWJGLKeycode.execKey(event, event.getKeyCode(), true); - break; - - case KeyEvent.ACTION_UP: - AndroidLWJGLKeycode.execKey(event, event.getKeyCode(), false); - break; - } - - return super.dispatchKeyEvent(event); - } - */ + @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) { int mouseCursorIndex = -1; - if(ev.getSource() == InputDevice.SOURCE_CLASS_JOYSTICK) { - CallbackBridge.nativePutControllerAxes((FloatBuffer)FloatBuffer.allocate(8) - .put(ev.getAxisValue(MotionEvent.AXIS_X)) - .put(ev.getAxisValue(MotionEvent.AXIS_Y)) - .put(ev.getAxisValue(MotionEvent.AXIS_Z)) - .put(ev.getAxisValue(MotionEvent.AXIS_RX)) - .put(ev.getAxisValue(MotionEvent.AXIS_RY)) - .put(ev.getAxisValue(MotionEvent.AXIS_RZ)) - .put(ev.getAxisValue(MotionEvent.AXIS_HAT_X)) - .put(ev.getAxisValue(MotionEvent.AXIS_HAT_Y)) - .flip()); - return true;//consume the cum chalice - }else { - for(int i = 0; i < ev.getPointerCount(); i++) { - if(ev.getToolType(i) == MotionEvent.TOOL_TYPE_MOUSE) { - mouseCursorIndex = i; - } - } - if(mouseCursorIndex == -1) return false; // we cant consoom that, theres no mice! - if(CallbackBridge.isGrabbing()) { - if(BaseMainActivity.isAndroid8OrHigher()) minecraftGLView.requestPointerCapture(); - } - switch(ev.getActionMasked()) { - case MotionEvent.ACTION_HOVER_MOVE: - mouse_x = (int) (ev.getX(mouseCursorIndex) * scaleFactor); - mouse_y = (int) (ev.getY(mouseCursorIndex) * scaleFactor); - CallbackBridge.mouseX = mouse_x; - CallbackBridge.mouseY = mouse_y; - CallbackBridge.sendCursorPos(mouse_x,mouse_y); - debugText.setText(CallbackBridge.DEBUG_STRING.toString()); - CallbackBridge.DEBUG_STRING.setLength(0); - return true; - case MotionEvent.ACTION_SCROLL: - CallbackBridge.sendScroll((double) ev.getAxisValue(MotionEvent.AXIS_VSCROLL), (double) ev.getAxisValue(MotionEvent.AXIS_HSCROLL)); - return true; - case MotionEvent.ACTION_BUTTON_PRESS: - return sendMouseButtonUnconverted(ev.getActionButton(),true); - case MotionEvent.ACTION_BUTTON_RELEASE: - return sendMouseButtonUnconverted(ev.getActionButton(),false); - default: - return false; + + if(Gamepad.isGamepadEvent(ev)){ + if(gamepad == null){ + gamepad = new Gamepad(this, ev.getDevice()); } + + gamepad.update(ev); + return true; } - } - boolean isKeyboard(KeyEvent evt) { - System.out.println("Event:" +evt); - //if((evt.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD) return true; - //if(evt.getSource() == InputDevice.SOURCE_KEYBOARD) return true; - //if(evt.getUnicodeChar() != 0) return true; - if(AndroidLWJGLKeycode.androidToLwjglMap.containsKey(evt.getKeyCode())) return true; - return false; - } - byte[] kevArray = new byte[8]; - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - System.out.println(event.getSource() + " "+ event.getFlags()); - if(event.getSource() == InputDevice.SOURCE_CLASS_JOYSTICK) { - switch(event.getKeyCode()) { - case KeyEvent.KEYCODE_BUTTON_A: - kevArray[0]= (byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_BUTTON_B: - kevArray[1]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_BUTTON_X: - kevArray[2]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_BUTTON_Y: - kevArray[3]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_DPAD_LEFT: - kevArray[4]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_DPAD_RIGHT: - kevArray[5]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_DPAD_UP: - kevArray[6]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); - case KeyEvent.KEYCODE_DPAD_DOWN: - kevArray[7]=(byte) ((event.getAction() == KeyEvent.ACTION_DOWN)?1:0); + for(int i = 0; i < ev.getPointerCount(); i++) { + if(ev.getToolType(i) == MotionEvent.TOOL_TYPE_MOUSE) { + mouseCursorIndex = i; + break; } - CallbackBridge.nativePutControllerButtons(ByteBuffer.wrap(kevArray)); - return true; - }else if(isKeyboard(event)) { - AndroidLWJGLKeycode.execKey(event,event.getKeyCode(),event.getAction() == KeyEvent.ACTION_DOWN); - return true; - }else return false; + } + if(mouseCursorIndex == -1) return false; // we cant consoom that, theres no mice! + if(CallbackBridge.isGrabbing()) { + if(BaseMainActivity.isAndroid8OrHigher()) minecraftGLView.requestPointerCapture(); + } + switch(ev.getActionMasked()) { + case MotionEvent.ACTION_HOVER_MOVE: + mouse_x = (ev.getX(mouseCursorIndex) * scaleFactor); + mouse_y = (ev.getY(mouseCursorIndex) * scaleFactor); + CallbackBridge.sendCursorPos(mouse_x, mouse_y); + debugText.setText(CallbackBridge.DEBUG_STRING.toString()); + CallbackBridge.DEBUG_STRING.setLength(0); + return true; + case MotionEvent.ACTION_SCROLL: + CallbackBridge.sendScroll((double) ev.getAxisValue(MotionEvent.AXIS_VSCROLL), (double) ev.getAxisValue(MotionEvent.AXIS_HSCROLL)); + return true; + case MotionEvent.ACTION_BUTTON_PRESS: + return sendMouseButtonUnconverted(ev.getActionButton(),true); + case MotionEvent.ACTION_BUTTON_RELEASE: + return sendMouseButtonUnconverted(ev.getActionButton(),false); + default: + return false; + } + + } - //private Dialog menuDial; + boolean isKeyboard(KeyEvent evt) { + System.out.println("Event:" +evt); + return EfficientAndroidLWJGLKeycode.containsKey(evt.getKeyCode()); + } + + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if(event.getRepeatCount() != 0 || event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN || (event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK) return true; //We consume but no need to recheck since it was already sent once. + System.out.println(event); + + if(Gamepad.isGamepadEvent(event)){ + if(gamepad == null){ + gamepad = new Gamepad(this, event.getDevice()); + } + + gamepad.update(event); + return true; + } + + int index = EfficientAndroidLWJGLKeycode.getIndexByKey(event.getKeyCode()); + if(index >= 0) { + //Toast.makeText(this,"THIS IS A KEYBOARD EVENT !", Toast.LENGTH_SHORT).show(); + EfficientAndroidLWJGLKeycode.execKey(event, index); + return true; + } + + return false; + } + + @Override public void onResume() { super.onResume(); mIsResuming = true; - // if (minecraftGLView != null) minecraftGLView.requestRender(); final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; final View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility(uiOptions); } @Override - protected void onPause() - { + protected void onPause() { if (CallbackBridge.isGrabbing()){ sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ESCAPE); } @@ -884,29 +664,7 @@ public class BaseMainActivity extends LoggableActivity { return Build.VERSION.SDK_INT >= 26; } - // private FileObserver mLogObserver; private void runCraft() throws Throwable { - /* Old logger - if (Tools.LAUNCH_TYPE != Tools.LTYPE_PROCESS) { - currLogFile = JREUtils.redirectStdio(true); - // DEPRECATED constructor (String) api 29 - mLogObserver = new FileObserver(currLogFile.getAbsolutePath(), FileObserver.MODIFY){ - @Override - public void onEvent(int event, String file) { - try { - if (event == FileObserver.MODIFY && currLogFile.length() > 0l) { - System.out.println(Tools.read(currLogFile.getAbsolutePath())); - Tools.write(currLogFile.getAbsolutePath(), ""); - } - } catch (Throwable th) { - Tools.showError(MainActivity.this, th); - mLogObserver.stopWatching(); - } - } - }; - mLogObserver.startWatching(); - } - */ if(Tools.LOCAL_RENDERER == null) { Tools.LOCAL_RENDERER = LauncherPreferences.PREF_RENDERER; } @@ -932,38 +690,6 @@ public class BaseMainActivity extends LoggableActivity { private void checkJavaArgsIsLaunchable(String jreVersion) throws Throwable { appendlnToLog("Info: Custom Java arguments: \"" + LauncherPreferences.PREF_CUSTOM_JAVA_ARGS + "\""); - -/* - if (jreVersion.equals("1.8.0")) return; - - // Test java - ShellProcessOperation shell = new ShellProcessOperation(new ShellProcessOperation.OnPrintListener(){ - @Override - public void onPrintLine(String text){ - appendlnToLog("[JRETest] " + text); - } - }); - JREUtils.setJavaEnvironment(this, shell); - - List testArgs = new ArrayList(); - testArgs.add(Tools.homeJreDir + "/bin/java"); - Tools.getJavaArgs(this, testArgs); - testArgs.add("-version"); - - new File(Tools.homeJreDir + "/bin/java").setExecutable(true); - - // shell.writeToProcess("chmod 777 " + Tools.homeJreDir + "/bin/java"); - shell.writeToProcess("set -e"); - shell.writeToProcess(testArgs.toArray(new String[0])); - - int exitCode = shell.waitFor(); - appendlnToLog("Info: java test command exited with " + exitCode); - - if (exitCode != 0) { - appendlnToLog("Error: the test returned non-zero exit code."); - // throw new RuntimeException(getString(R.string.mcn_check_fail_java)); - } - */ } private void checkLWJGL3Installed() { @@ -999,11 +725,11 @@ public class BaseMainActivity extends LoggableActivity { } public static String fromArray(List arr) { - String s = ""; + StringBuilder s = new StringBuilder(); for (String exec : arr) { - s = s + " " + exec; + s.append(" ").append(exec); } - return s; + return s.toString(); } private void toggleDebug() { @@ -1013,15 +739,10 @@ public class BaseMainActivity extends LoggableActivity { private void dialogSendCustomKey() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle(R.string.control_customkey); - dialog.setItems(AndroidLWJGLKeycode.generateKeyName(), new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface dInterface, int position) { - AndroidLWJGLKeycode.execKeyIndex(BaseMainActivity.this, position); - } - }); + dialog.setItems(EfficientAndroidLWJGLKeycode.generateKeyName(), (dInterface, position) -> EfficientAndroidLWJGLKeycode.execKeyIndex(position)); dialog.show(); } + boolean isInEditor; private void openCustomControls() { if(ingameControlsEditorListener != null) { @@ -1032,6 +753,7 @@ public class BaseMainActivity extends LoggableActivity { isInEditor = true; } } + public void leaveCustomControls() { if(this instanceof MainActivity) { try { @@ -1059,66 +781,34 @@ public class BaseMainActivity extends LoggableActivity { contentLog.setVisibility(View.GONE); mIsResuming = true; } - /* - private void openCanvasOutput() { - WindowAnimation.fadeIn(contentCanvas, 500); - } - - public void closeCanvasOutput(View view) { - WindowAnimation.fadeOut(contentCanvas, 500); - } - */ @Override public void appendToLog(final String text, boolean checkAllow) { logStream.print(text); if (checkAllow && !isLogAllow) return; - textLog.post(new Runnable(){ - @Override - public void run() { - textLog.append(text); - contentScroll.fullScroll(ScrollView.FOCUS_DOWN); - } - }); - } - - public String getMinecraftOption(String key) { - try { - String[] options = Tools.read(Tools.DIR_GAME_NEW + "/options.txt").split("\n"); - for (String option : options) { - String[] optionKeyValue = option.split(":"); - if (optionKeyValue[0].equals(key)) { - return optionKeyValue[1]; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return ""; + textLog.post(() -> { + textLog.append(text); + contentScroll.fullScroll(ScrollView.FOCUS_DOWN); + }); } public int mcscale(int input) { return (int)((this.guiScale * input)/scaleFactor); } - /* - public int randomInRange(int min, int max) { - return min + (int)(Math.random() * (max - min + 1)); - } - */ public void toggleMenu(View v) { drawerLayout.openDrawer(Gravity.RIGHT); } public void placeMouseAdd(float x, float y) { - this.mousePointer.setTranslationX(mousePointer.getTranslationX() + x); - this.mousePointer.setTranslationY(mousePointer.getTranslationY() + y); + this.mousePointer.setX(mousePointer.getX() + x); + this.mousePointer.setY(mousePointer.getY() + y); } public void placeMouseAt(float x, float y) { - this.mousePointer.setTranslationX(x); - this.mousePointer.setTranslationY(y); + this.mousePointer.setX(x); + this.mousePointer.setY(y); } public void toggleMouse(View view) { @@ -1133,24 +823,13 @@ public class BaseMainActivity extends LoggableActivity { new AlertDialog.Builder(ctx) .setMessage(R.string.mcn_exit_confirm) .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface p1, int p2) - { - try { - fullyExit(); - } catch (Throwable th) { - Log.w(Tools.APP_NAME, "Could not enable System.exit() method!", th); - } - - // If we are unable to enable exit, use method: kill myself. - // android.os.Process.killProcess(android.os.Process.myPid()); - - // Toast.makeText(MainActivity.this, "Could not exit. Please force close this app.", Toast.LENGTH_LONG).show(); + .setPositiveButton(android.R.string.ok, (p1, p2) -> { + try { + fullyExit(); + } catch (Throwable th) { + Log.w(Tools.APP_NAME, "Could not enable System.exit() method!", th); } - }) - .show(); + }).show(); } @Override @@ -1179,7 +858,6 @@ public class BaseMainActivity extends LoggableActivity { protected void setRightOverride(boolean val) { this.rightOverride = val; - // this.secondaryButton.setBackgroundDrawable(this.rightOverride ? this.secondaryButtonColorBackground : this.secondaryButtonDefaultBackground); } public static void sendKeyPress(int keyCode, int modifiers, boolean status) { @@ -1205,18 +883,19 @@ public class BaseMainActivity extends LoggableActivity { if(doesObjectContainField(KeyEvent.class,"KEYCODE_" + Character.toUpperCase(keyChar))) { try { int keyCode = KeyEvent.class.getField("KEYCODE_" + Character.toUpperCase(keyChar)).getInt(null); - sendKeyPress(AndroidLWJGLKeycode.androidToLwjglMap.get(keyCode), keyChar, 0, CallbackBridge.getCurrentMods(), true); - sendKeyPress(AndroidLWJGLKeycode.androidToLwjglMap.get(keyCode), keyChar, 0, CallbackBridge.getCurrentMods(), false); + sendKeyPress(EfficientAndroidLWJGLKeycode.getValue(keyCode), keyChar, 0, CallbackBridge.getCurrentMods(), true); + sendKeyPress(EfficientAndroidLWJGLKeycode.getValue(keyCode), keyChar, 0, CallbackBridge.getCurrentMods(), false); } catch (IllegalAccessException | NoSuchFieldException e) { } - }else{ - sendKeyPress(0, keyChar, 0, CallbackBridge.getCurrentMods(), true); - sendKeyPress(0, keyChar, 0, CallbackBridge.getCurrentMods(), false); + return; } + + sendKeyPress(0, keyChar, 0, CallbackBridge.getCurrentMods(), true); + sendKeyPress(0, keyChar, 0, CallbackBridge.getCurrentMods(), false); } - public void sendKeyPress(int keyCode) { + public static void sendKeyPress(int keyCode) { sendKeyPress(keyCode, CallbackBridge.getCurrentMods(), true); sendKeyPress(keyCode, CallbackBridge.getCurrentMods(), false); } @@ -1243,7 +922,7 @@ public class BaseMainActivity extends LoggableActivity { return true; } - public void getMcScale() { + public int getMcScale() { //Get the scale stored in game files, used auto scale if found or if the stored scaled is bigger than the authorized size. MCOptionUtils.load(); String str = MCOptionUtils.get("guiScale"); @@ -1254,6 +933,9 @@ public class BaseMainActivity extends LoggableActivity { if(scale < this.guiScale || guiScale == 0){ this.guiScale = scale; } + + if(gamepad != null) gamepad.notifyGUISizeChange(this.guiScale); + return this.guiScale; } public int handleGuiBar(int x, int y) { @@ -1292,21 +974,15 @@ public class BaseMainActivity extends LoggableActivity { public void onStopTrackingTouch(SeekBar seekBar) {} }); b.setView(v); - b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - LauncherPreferences.PREF_MOUSESPEED = ((float)tmpMouseSpeed)/100f; - LauncherPreferences.DEFAULT_PREF.edit().putInt("mousespeed",tmpMouseSpeed).commit(); - dialogInterface.dismiss(); - System.gc(); - } + b.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { + LauncherPreferences.PREF_MOUSESPEED = ((float)tmpMouseSpeed)/100f; + LauncherPreferences.DEFAULT_PREF.edit().putInt("mousespeed",tmpMouseSpeed).commit(); + dialogInterface.dismiss(); + System.gc(); }); - b.setNegativeButton(android.R.string.cancel,new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - System.gc(); - } + b.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> { + dialogInterface.dismiss(); + System.gc(); }); b.show(); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java index 02b28c689..26dfe44f3 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java @@ -60,7 +60,10 @@ public class CustomControlsActivity extends BaseActivity load(ctrlLayout); break; case R.id.menu_ctrl_add: - ctrlLayout.addControlButton(new ControlData("New", LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, 100, 100)); + ctrlLayout.addControlButton(new ControlData("New")); + break; + case R.id.menu_ctrl_add_drawer: + ctrlLayout.addDrawer(new ControlDrawerData()); break; case R.id.menu_ctrl_selectdefault: dialogSelectDefaultCtrl(ctrlLayout); @@ -150,6 +153,7 @@ public class CustomControlsActivity extends BaseActivity if(ctx instanceof MainActivity) { ((MainActivity) ctx).leaveCustomControls(); }else{ + ((CustomControlsActivity) ctx).isModified = false; ((Activity)ctx).onBackPressed(); } // setResult(Activity.RESULT_OK, new Intent()); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/EfficientAndroidLWJGLKeycode.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/EfficientAndroidLWJGLKeycode.java new file mode 100644 index 000000000..1bae86893 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/EfficientAndroidLWJGLKeycode.java @@ -0,0 +1,239 @@ +package net.kdt.pojavlaunch; + +import android.view.KeyEvent; + +import net.kdt.pojavlaunch.prefs.LauncherPreferences; + +import org.lwjgl.glfw.CallbackBridge; + +import java.util.Arrays; + +public class EfficientAndroidLWJGLKeycode { + + //This old version of this class was using an ArrayMap, a generic Key -> Value data structure. + //The key being the android keycode from a KeyEvent + //The value its LWJGL equivalent. + private static final int KEYCODE_COUNT = 102; + private static final int[] androidKeycodes = new int[KEYCODE_COUNT]; + private static final short[] LWJGLKeycodes = new short[KEYCODE_COUNT]; + private static String[] androidKeyNameArray; /* = new String[androidKeycodes.length]; */ + + static { + /* BINARY SEARCH IS PERFORMED ON THE androidKeycodes ARRAY ! + WHEN ADDING A MAPPING, ADD IT SO THE androidKeycodes ARRAY STAYS SORTED ! */ + // Mapping Android Keycodes to LWJGL Keycodes + add(KeyEvent.KEYCODE_UNKNOWN,LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN); + add(KeyEvent.KEYCODE_HOME, LWJGLGLFWKeycode.GLFW_KEY_HOME); + // Escape key + add(KeyEvent.KEYCODE_BACK, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE); + + // 0-9 keys + add(KeyEvent.KEYCODE_0, LWJGLGLFWKeycode.GLFW_KEY_0); //7 + add(KeyEvent.KEYCODE_1, LWJGLGLFWKeycode.GLFW_KEY_1); + add(KeyEvent.KEYCODE_2, LWJGLGLFWKeycode.GLFW_KEY_2); + add(KeyEvent.KEYCODE_3, LWJGLGLFWKeycode.GLFW_KEY_3); + add(KeyEvent.KEYCODE_4, LWJGLGLFWKeycode.GLFW_KEY_4); + add(KeyEvent.KEYCODE_5, LWJGLGLFWKeycode.GLFW_KEY_5); + add(KeyEvent.KEYCODE_6, LWJGLGLFWKeycode.GLFW_KEY_6); + add(KeyEvent.KEYCODE_7, LWJGLGLFWKeycode.GLFW_KEY_7); + add(KeyEvent.KEYCODE_8, LWJGLGLFWKeycode.GLFW_KEY_8); + add(KeyEvent.KEYCODE_9, LWJGLGLFWKeycode.GLFW_KEY_9); //16 + + add(KeyEvent.KEYCODE_POUND,LWJGLGLFWKeycode.GLFW_KEY_3); + + // Arrow keys + add(KeyEvent.KEYCODE_DPAD_UP, LWJGLGLFWKeycode.GLFW_KEY_UP); //19 + add(KeyEvent.KEYCODE_DPAD_DOWN, LWJGLGLFWKeycode.GLFW_KEY_DOWN); + add(KeyEvent.KEYCODE_DPAD_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT); + add(KeyEvent.KEYCODE_DPAD_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT); //22 + + // A-Z keys + add(KeyEvent.KEYCODE_A, LWJGLGLFWKeycode.GLFW_KEY_A); //29 + add(KeyEvent.KEYCODE_B, LWJGLGLFWKeycode.GLFW_KEY_B); + add(KeyEvent.KEYCODE_C, LWJGLGLFWKeycode.GLFW_KEY_C); + add(KeyEvent.KEYCODE_D, LWJGLGLFWKeycode.GLFW_KEY_D); + add(KeyEvent.KEYCODE_E, LWJGLGLFWKeycode.GLFW_KEY_E); + add(KeyEvent.KEYCODE_F, LWJGLGLFWKeycode.GLFW_KEY_F); + add(KeyEvent.KEYCODE_G, LWJGLGLFWKeycode.GLFW_KEY_G); + add(KeyEvent.KEYCODE_H, LWJGLGLFWKeycode.GLFW_KEY_H); + add(KeyEvent.KEYCODE_I, LWJGLGLFWKeycode.GLFW_KEY_I); + add(KeyEvent.KEYCODE_J, LWJGLGLFWKeycode.GLFW_KEY_J); + add(KeyEvent.KEYCODE_K, LWJGLGLFWKeycode.GLFW_KEY_K); + add(KeyEvent.KEYCODE_L, LWJGLGLFWKeycode.GLFW_KEY_L); + add(KeyEvent.KEYCODE_M, LWJGLGLFWKeycode.GLFW_KEY_M); + add(KeyEvent.KEYCODE_N, LWJGLGLFWKeycode.GLFW_KEY_N); + add(KeyEvent.KEYCODE_O, LWJGLGLFWKeycode.GLFW_KEY_O); + add(KeyEvent.KEYCODE_P, LWJGLGLFWKeycode.GLFW_KEY_P); + add(KeyEvent.KEYCODE_Q, LWJGLGLFWKeycode.GLFW_KEY_Q); + add(KeyEvent.KEYCODE_R, LWJGLGLFWKeycode.GLFW_KEY_R); + add(KeyEvent.KEYCODE_S, LWJGLGLFWKeycode.GLFW_KEY_S); + add(KeyEvent.KEYCODE_T, LWJGLGLFWKeycode.GLFW_KEY_T); + add(KeyEvent.KEYCODE_U, LWJGLGLFWKeycode.GLFW_KEY_U); + add(KeyEvent.KEYCODE_V, LWJGLGLFWKeycode.GLFW_KEY_V); + add(KeyEvent.KEYCODE_W, LWJGLGLFWKeycode.GLFW_KEY_W); + add(KeyEvent.KEYCODE_X, LWJGLGLFWKeycode.GLFW_KEY_X); + add(KeyEvent.KEYCODE_Y, LWJGLGLFWKeycode.GLFW_KEY_Y); + add(KeyEvent.KEYCODE_Z, LWJGLGLFWKeycode.GLFW_KEY_Z); //54 + + + add(KeyEvent.KEYCODE_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA); + + // Alt keys + add(KeyEvent.KEYCODE_ALT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT); + add(KeyEvent.KEYCODE_ALT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_ALT); + + // Shift keys + add(KeyEvent.KEYCODE_SHIFT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT); + add(KeyEvent.KEYCODE_SHIFT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_SHIFT); + + add(KeyEvent.KEYCODE_TAB, LWJGLGLFWKeycode.GLFW_KEY_TAB); + add(KeyEvent.KEYCODE_SPACE, LWJGLGLFWKeycode.GLFW_KEY_SPACE); + add(KeyEvent.KEYCODE_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER); //66 + add(KeyEvent.KEYCODE_DEL, LWJGLGLFWKeycode.GLFW_KEY_BACKSPACE); // Backspace + add(KeyEvent.KEYCODE_GRAVE, LWJGLGLFWKeycode.GLFW_KEY_GRAVE_ACCENT); + add(KeyEvent.KEYCODE_MINUS, LWJGLGLFWKeycode.GLFW_KEY_MINUS); + add(KeyEvent.KEYCODE_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL); + add(KeyEvent.KEYCODE_LEFT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_LEFT_BRACKET); + add(KeyEvent.KEYCODE_RIGHT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_BRACKET); + add(KeyEvent.KEYCODE_BACKSLASH, LWJGLGLFWKeycode.GLFW_KEY_BACKSLASH); + add(KeyEvent.KEYCODE_SEMICOLON, LWJGLGLFWKeycode.GLFW_KEY_SEMICOLON); //74 + + add(KeyEvent.KEYCODE_SLASH, LWJGLGLFWKeycode.GLFW_KEY_SLASH); //76 + add(KeyEvent.KEYCODE_AT,LWJGLGLFWKeycode.GLFW_KEY_2); + + add(KeyEvent.KEYCODE_PLUS, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD); + + // Page keys + add(KeyEvent.KEYCODE_PAGE_UP, LWJGLGLFWKeycode.GLFW_KEY_PAGE_UP); //92 + add(KeyEvent.KEYCODE_PAGE_DOWN, LWJGLGLFWKeycode.GLFW_KEY_PAGE_DOWN); + + add(KeyEvent.KEYCODE_ESCAPE, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE); + + // Control keys + add(KeyEvent.KEYCODE_CTRL_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL); + add(KeyEvent.KEYCODE_CTRL_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_CONTROL); + + add(KeyEvent.KEYCODE_CAPS_LOCK, LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK); + add(KeyEvent.KEYCODE_BREAK, LWJGLGLFWKeycode.GLFW_KEY_PAUSE); + add(KeyEvent.KEYCODE_INSERT, LWJGLGLFWKeycode.GLFW_KEY_INSERT); + + // Fn keys + add(KeyEvent.KEYCODE_F1, LWJGLGLFWKeycode.GLFW_KEY_F1); //131 + add(KeyEvent.KEYCODE_F2, LWJGLGLFWKeycode.GLFW_KEY_F2); + add(KeyEvent.KEYCODE_F3, LWJGLGLFWKeycode.GLFW_KEY_F3); + add(KeyEvent.KEYCODE_F4, LWJGLGLFWKeycode.GLFW_KEY_F4); + add(KeyEvent.KEYCODE_F5, LWJGLGLFWKeycode.GLFW_KEY_F5); + add(KeyEvent.KEYCODE_F6, LWJGLGLFWKeycode.GLFW_KEY_F6); + add(KeyEvent.KEYCODE_F7, LWJGLGLFWKeycode.GLFW_KEY_F7); + add(KeyEvent.KEYCODE_F8, LWJGLGLFWKeycode.GLFW_KEY_F8); + add(KeyEvent.KEYCODE_F9, LWJGLGLFWKeycode.GLFW_KEY_F9); + add(KeyEvent.KEYCODE_F10, LWJGLGLFWKeycode.GLFW_KEY_F10); + add(KeyEvent.KEYCODE_F11, LWJGLGLFWKeycode.GLFW_KEY_F11); + add(KeyEvent.KEYCODE_F12, LWJGLGLFWKeycode.GLFW_KEY_F12); //142 + + // Num keys + add(KeyEvent.KEYCODE_NUM_LOCK, LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK); //143 + add(KeyEvent.KEYCODE_NUMPAD_0, LWJGLGLFWKeycode.GLFW_KEY_0); + add(KeyEvent.KEYCODE_NUMPAD_1, LWJGLGLFWKeycode.GLFW_KEY_1); + add(KeyEvent.KEYCODE_NUMPAD_2, LWJGLGLFWKeycode.GLFW_KEY_2); + add(KeyEvent.KEYCODE_NUMPAD_3, LWJGLGLFWKeycode.GLFW_KEY_3); + add(KeyEvent.KEYCODE_NUMPAD_4, LWJGLGLFWKeycode.GLFW_KEY_4); + add(KeyEvent.KEYCODE_NUMPAD_5, LWJGLGLFWKeycode.GLFW_KEY_5); + add(KeyEvent.KEYCODE_NUMPAD_6, LWJGLGLFWKeycode.GLFW_KEY_6); + add(KeyEvent.KEYCODE_NUMPAD_7, LWJGLGLFWKeycode.GLFW_KEY_7); + add(KeyEvent.KEYCODE_NUMPAD_8, LWJGLGLFWKeycode.GLFW_KEY_8); + add(KeyEvent.KEYCODE_NUMPAD_9, LWJGLGLFWKeycode.GLFW_KEY_9); + add(KeyEvent.KEYCODE_NUMPAD_DIVIDE, LWJGLGLFWKeycode.GLFW_KEY_KP_DIVIDE); + add(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, LWJGLGLFWKeycode.GLFW_KEY_KP_MULTIPLY); + add(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, LWJGLGLFWKeycode.GLFW_KEY_KP_SUBTRACT); + add(KeyEvent.KEYCODE_NUMPAD_ADD, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD); + add(KeyEvent.KEYCODE_NUMPAD_DOT, LWJGLGLFWKeycode.GLFW_KEY_PERIOD); + add(KeyEvent.KEYCODE_NUMPAD_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA); + add(KeyEvent.KEYCODE_NUMPAD_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER); + add(KeyEvent.KEYCODE_NUMPAD_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL); //161 + + } + + private static short index = 0; + + private static void add(int androidKeycode, short LWJGLKeycode){ + androidKeycodes[index] = androidKeycode; + LWJGLKeycodes[index] = LWJGLKeycode; + ++index; + } + + + public static boolean containsKey(int keycode){ + return getIndexByKey(keycode) >= 0; + } + + + + public static String[] generateKeyName() { + if (androidKeyNameArray == null) { + androidKeyNameArray = new String[androidKeycodes.length]; + for(int i=0; i < androidKeyNameArray.length; ++i){ + androidKeyNameArray[i] = KeyEvent.keyCodeToString(androidKeycodes[i]).replace("KEYCODE_", ""); + } + } + return androidKeyNameArray; + } + + public static void execKey(KeyEvent keyEvent) { + execKey(keyEvent, getIndexByKey(keyEvent.getKeyCode())); + } + + + public static void execKey(KeyEvent keyEvent, int valueIndex) { + //valueIndex points to where the value is stored in the array. + CallbackBridge.holdingAlt = keyEvent.isAltPressed(); + CallbackBridge.holdingCapslock = keyEvent.isCapsLockOn(); + CallbackBridge.holdingCtrl = keyEvent.isCtrlPressed(); + CallbackBridge.holdingNumlock = keyEvent.isNumLockOn(); + CallbackBridge.holdingShift = keyEvent.isShiftPressed(); + + try { + System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel()); + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && LauncherPreferences.PREF_BACK_TO_RIGHT_MOUSE) { + BaseMainActivity.sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, keyEvent.getAction() == KeyEvent.ACTION_DOWN); + } else { + char key = (char)(keyEvent.getUnicodeChar() != 0 ? keyEvent.getUnicodeChar() : '\u0000'); + BaseMainActivity.sendKeyPress( + getValueByIndex(valueIndex), + key, + 0, + CallbackBridge.getCurrentMods(), + keyEvent.getAction() == KeyEvent.ACTION_DOWN); + } + } catch (Throwable th) { + th.printStackTrace(); + } + } + + public static void execKeyIndex(int index){ + //Send a quick key press. + BaseMainActivity.sendKeyPress(getValueByIndex(index)); + } + + public static int getValueByIndex(int index) { + return LWJGLKeycodes[index]; + } + + public static int getIndexByKey(int key){ + return Arrays.binarySearch(androidKeycodes, key); + } + + public static short getValue(int key){ + return LWJGLKeycodes[Arrays.binarySearch(androidKeycodes, key)]; + } + + public static int getIndexByValue(int lwjglKey) { + //Since the LWJGL keycodes aren't sorted, linear search is used. + //You should avoid using this function on performance critical areas + for (int i = 0; i < LWJGLKeycodes.length; i++) { + if(LWJGLKeycodes[i] == lwjglKey) return i; + } + + return 0; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JavaGUILauncherActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JavaGUILauncherActivity.java index 77308e4da..cc3966114 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JavaGUILauncherActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JavaGUILauncherActivity.java @@ -108,8 +108,8 @@ public class JavaGUILauncherActivity extends LoggableActivity implements View.On prevX = x; prevY = y; } - float mouseX = mousePointer.getTranslationX(); - float mouseY = mousePointer.getTranslationY(); + float mouseX = mousePointer.getX(); + float mouseY = mousePointer.getY(); if (gestureDetector.onTouchEvent(event)) { @@ -250,13 +250,13 @@ public class JavaGUILauncherActivity extends LoggableActivity implements View.On } public void placeMouseAdd(float x, float y) { - this.mousePointer.setTranslationX(mousePointer.getTranslationX() + x); - this.mousePointer.setTranslationY(mousePointer.getTranslationY() + y); + this.mousePointer.setX(mousePointer.getX() + x); + this.mousePointer.setY(mousePointer.getY() + y); } public void placeMouseAt(float x, float y) { - this.mousePointer.setTranslationX(x); - this.mousePointer.setTranslationY(y); + this.mousePointer.setX(x); + this.mousePointer.setY(y); } void sendScaledMousePosition(float x, float y){ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LWJGLGLFWKeycode.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LWJGLGLFWKeycode.java index 39db81891..5482b01f6 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LWJGLGLFWKeycode.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LWJGLGLFWKeycode.java @@ -33,10 +33,10 @@ package net.kdt.pojavlaunch; public class LWJGLGLFWKeycode { /** The unknown key. */ - public static final int GLFW_KEY_UNKNOWN = 0; // should be -1 + public static final short GLFW_KEY_UNKNOWN = 0; // should be -1 /** Printable keys. */ - public static final int + public static final short GLFW_KEY_SPACE = 32, GLFW_KEY_APOSTROPHE = 39, GLFW_KEY_COMMA = 44, @@ -89,7 +89,7 @@ public class LWJGLGLFWKeycode GLFW_KEY_WORLD_2 = 162; /** Function keys. */ - public static final int + public static final short GLFW_KEY_ESCAPE = 256, GLFW_KEY_ENTER = 257, GLFW_KEY_TAB = 258, @@ -182,7 +182,7 @@ public class LWJGLGLFWKeycode /** Mouse buttons. See mouse button input for how these are used. */ - public static final int + public static final short GLFW_MOUSE_BUTTON_1 = 0, GLFW_MOUSE_BUTTON_2 = 1, GLFW_MOUSE_BUTTON_3 = 2, diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MainActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MainActivity.java index 67cdcd63a..f63c0dd98 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MainActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MainActivity.java @@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import com.google.android.material.navigation.NavigationView; import net.kdt.pojavlaunch.customcontrols.*; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; import net.kdt.pojavlaunch.prefs.*; import net.kdt.pojavlaunch.utils.MCOptionUtils; @@ -37,7 +38,10 @@ public class MainActivity extends BaseMainActivity { CustomControlsActivity.load(mControlLayout); break; case R.id.menu_ctrl_add: - mControlLayout.addControlButton(new ControlData("New", LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, 100, 100)); + mControlLayout.addControlButton(new ControlData("New")); + break; + case R.id.menu_ctrl_add_drawer: + mControlLayout.addDrawer(new ControlDrawerData()); break; case R.id.menu_ctrl_selectdefault: CustomControlsActivity.dialogSelectDefaultCtrl(mControlLayout); @@ -56,18 +60,20 @@ public class MainActivity extends BaseMainActivity { public void onClick(View view) { if (view instanceof ControlButton) { ControlButton button = (ControlButton) view; - switch (button.getProperties().keycode) { - case ControlData.SPECIALBTN_KEYBOARD: - showKeyboard(); - break; + for(int keycode : button.getProperties().keycodes){ + switch (keycode) { + case ControlData.SPECIALBTN_KEYBOARD: + showKeyboard(); + break; - case ControlData.SPECIALBTN_TOGGLECTRL: - mControlLayout.toggleControlVisible(); - break; + case ControlData.SPECIALBTN_TOGGLECTRL: + mControlLayout.toggleControlVisible(); + break; - case ControlData.SPECIALBTN_VIRTUALMOUSE: - toggleMouse(button); - break; + case ControlData.SPECIALBTN_VIRTUALMOUSE: + toggleMouse(button); + break; + } } } } @@ -93,32 +99,34 @@ public class MainActivity extends BaseMainActivity { if (view instanceof ControlButton) { ControlButton button = (ControlButton) view; - switch (button.getProperties().keycode) { - case ControlData.SPECIALBTN_MOUSEPRI: - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown); - break; + for(int keycode : button.getProperties().keycodes) { + switch (keycode) { + case ControlData.SPECIALBTN_MOUSEPRI: + sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown); + break; - case ControlData.SPECIALBTN_MOUSEMID: - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown); - break; + case ControlData.SPECIALBTN_MOUSEMID: + sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown); + break; - case ControlData.SPECIALBTN_MOUSESEC: - if (CallbackBridge.isGrabbing()) { - sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown); - } else { - CallbackBridge.putMouseEventWithCoords(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown ? 1 : 0, CallbackBridge.mouseX, CallbackBridge.mouseY); + case ControlData.SPECIALBTN_MOUSESEC: + if (CallbackBridge.isGrabbing()) { + sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown); + } else { + CallbackBridge.putMouseEventWithCoords(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown ? 1 : 0, CallbackBridge.mouseX, CallbackBridge.mouseY); - setRightOverride(isDown); - } - break; - - case ControlData.SPECIALBTN_SCROLLDOWN: - if(!isDown)CallbackBridge.sendScroll(0, 1d); - break; - - case ControlData.SPECIALBTN_SCROLLUP: - if(!isDown)CallbackBridge.sendScroll(0, -1d); - break; + setRightOverride(isDown); + } + break; + + case ControlData.SPECIALBTN_SCROLLDOWN: + if (!isDown) CallbackBridge.sendScroll(0, 1d); + break; + + case ControlData.SPECIALBTN_SCROLLUP: + if (!isDown) CallbackBridge.sendScroll(0, -1d); + break; + } } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 4ea68c69e..83b95c7bd 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -33,8 +33,7 @@ import static android.os.Build.VERSION_CODES.P; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_IGNORE_NOTCH; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE; -public final class Tools -{ +public final class Tools { public static final boolean ENABLE_DEV_FEATURES = BuildConfig.DEBUG; public static String APP_NAME = "null"; @@ -417,10 +416,13 @@ public final class Tools } public static float dpToPx(float dp) { - // 921600 = 1280 * 720, default scale - // TODO better way to scaling - float scaledDp = dp; // / DisplayMetrics.DENSITY_XHIGH * currentDisplayMetrics.densityDpi; - return (scaledDp * currentDisplayMetrics.density); + //Better hope for the currentDisplayMetrics to be good + return dp * currentDisplayMetrics.density; + } + + public static float pxToDp(float px){ + //Better hope for the currentDisplayMetrics to be good + return px / currentDisplayMetrics.density; } public static void copyAssetFile(Context ctx, String fileName, String output, boolean overwrite) throws IOException { @@ -438,31 +440,7 @@ public final class Tools write(file2.getAbsolutePath(), loadFromAssetToByte(ctx, fileName)); } } -/* - public static void extractAssetFolder(Activity ctx, String path, String output) throws Exception { - extractAssetFolder(ctx, path, output, false); - } - public static void extractAssetFolder(Activity ctx, String path, String output, boolean overwrite) throws Exception { - AssetManager assetManager = ctx.getAssets(); - String assets[] = null; - try { - assets = assetManager.list(path); - if (assets.length == 0) { - Tools.copyAssetFile(ctx, path, output, overwrite); - } else { - File dir = new File(output, path); - if (!dir.exists()) - dir.mkdirs(); - for (String sub : assets) { - extractAssetFolder(ctx, path + "/" + sub, output, overwrite); - } - } - } catch (Exception e) { - showError(ctx, e); - } - } -*/ public static void showError(Context ctx, Throwable e) { showError(ctx, e, false); } @@ -487,45 +465,27 @@ public final class Tools AlertDialog.Builder builder = new AlertDialog.Builder((Context) ctx) .setTitle(titleId) .setMessage(errMsg) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface p1, int p2) - { - if(exitIfOk) { - if (ctx instanceof BaseMainActivity) { - BaseMainActivity.fullyExit(); - } else if (ctx instanceof Activity) { - ((Activity) ctx).finish(); - } + .setPositiveButton(android.R.string.ok, (DialogInterface.OnClickListener) (p1, p2) -> { + if(exitIfOk) { + if (ctx instanceof BaseMainActivity) { + BaseMainActivity.fullyExit(); + } else if (ctx instanceof Activity) { + ((Activity) ctx).finish(); } } }) - .setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface p1, int p2) - { - showError(ctx, titleId, e, exitIfOk, !showMore); - } - }) - .setNeutralButton(android.R.string.copy, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface p1, int p2) - { - android.content.ClipboardManager mgr = (android.content.ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); - mgr.setPrimaryClip(ClipData.newPlainText("error", Log.getStackTraceString(e))); - if(exitIfOk) { - if (ctx instanceof BaseMainActivity) { - BaseMainActivity.fullyExit(); - } else { - ((Activity) ctx).finish(); - } + .setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, (DialogInterface.OnClickListener) (p1, p2) -> showError(ctx, titleId, e, exitIfOk, !showMore)) + .setNeutralButton(android.R.string.copy, (DialogInterface.OnClickListener) (p1, p2) -> { + ClipboardManager mgr = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); + mgr.setPrimaryClip(ClipData.newPlainText("error", Log.getStackTraceString(e))); + if(exitIfOk) { + if (ctx instanceof BaseMainActivity) { + BaseMainActivity.fullyExit(); + } else { + ((Activity) ctx).finish(); } } }) - //.setNegativeButton("Report (not available)", null) .setCancelable(!exitIfOk); try { builder.show(); @@ -543,18 +503,11 @@ public final class Tools } public static void dialogOnUiThread(final Activity ctx, final CharSequence title, final CharSequence message) { - ctx.runOnUiThread(new Runnable(){ - - @Override - public void run() { - new AlertDialog.Builder(ctx) - .setTitle(title) - .setMessage(message) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - }); - + ctx.runOnUiThread(() -> new AlertDialog.Builder(ctx) + .setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.ok, null) + .show()); } public static void moveInside(String from, String to) { @@ -919,5 +872,5 @@ public final class Tools Tools.updateWindowSize(ctx); } } - + } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlButton.java deleted file mode 100644 index d0274a4fb..000000000 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlButton.java +++ /dev/null @@ -1,277 +0,0 @@ -package net.kdt.pojavlaunch.customcontrols; - -import android.content.*; -import android.graphics.*; -import android.util.*; -import android.view.*; -import android.view.View.*; -import android.widget.*; -import net.kdt.pojavlaunch.customcontrols.handleview.*; -import net.kdt.pojavlaunch.prefs.LauncherPreferences; -import net.kdt.pojavlaunch.*; -import org.lwjgl.glfw.*; - -public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener -{ - private Paint mRectPaint; - - private GestureDetector mGestureDetector; - private ControlData mProperties; - private SelectionEndHandleView mHandleView; - - private boolean mModifiable = false; - private boolean mCanTriggerLongClick = true; - - private boolean mChecked = false; - - private float mScaleAt; - - public ControlButton(ControlLayout layout, ControlData properties) { - super(layout.getContext()); - setPadding(4, 4, 4, 4); - setWillNotDraw(false); - - mScaleAt = layout.mLayout.scaledAt; - - mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm()); - - if (!LauncherPreferences.PREF_BUTTON_FLAT) { - setBackgroundResource(R.drawable.control_button); - } else { - setBackgroundResource(R.drawable.control_button_black); - } - setOnLongClickListener(this); - - setProperties(properties); - setModified(false); - - mHandleView = new SelectionEndHandleView(this); - - final TypedValue value = new TypedValue(); - getContext().getTheme().resolveAttribute(R.attr.colorAccent, value, true); - - mRectPaint = new Paint(); - mRectPaint.setColor(value.data); - mRectPaint.setAlpha(128); - } - - public HandleView getHandleView() { - return mHandleView; - } - - public ControlData getProperties() { - return mProperties; - } - - public void setProperties(ControlData properties) { - setProperties(properties, true); - } - - public void setProperties(ControlData properties, boolean changePos) { - mProperties = properties; - mProperties.transparency = mProperties.hidden ? 100 : mProperties.transparency; - properties.update(); - - // com.android.internal.R.string.delete - // android.R.string. - setText(properties.name); - if (changePos) { - setTranslationX(moveX = properties.x); - setTranslationY(moveY = properties.y); - } - if (!LauncherPreferences.PREF_BUTTON_FLAT) { - setBackgroundResource(mProperties.isRound ? R.drawable.control_button_round : R.drawable.control_button); - } else { - setBackgroundResource(mProperties.isRound ? R.drawable.control_button_round_black : R.drawable.control_button_black); - } - if (properties.specialButtonListener == null) { - // A non-special button or inside custom controls screen so skip listener - } else if (properties.specialButtonListener instanceof View.OnClickListener) { - setOnClickListener((View.OnClickListener) properties.specialButtonListener); - // setOnLongClickListener(null); - // setOnTouchListener(null); - } else if (properties.specialButtonListener instanceof View.OnTouchListener) { - // setOnLongClickListener(null); - setOnTouchListener((View.OnTouchListener) properties.specialButtonListener); - } else { - throw new IllegalArgumentException("Field " + ControlData.class.getName() + ".specialButtonListener must be View.OnClickListener or View.OnTouchListener, but was " + - properties.specialButtonListener.getClass().getName()); - } - - setLayoutParams(new FrameLayout.LayoutParams((int) properties.width, (int) properties.height)); - } - - @Override - public void setLayoutParams(ViewGroup.LayoutParams params) { - super.setLayoutParams(params); - - mProperties.width = params.width; - mProperties.height = params.height; - - // Re-calculate position - mProperties.update(); - setTranslationX(mProperties.x); - setTranslationY(mProperties.y); - - setModified(true); - } - - @Override - public void setTranslationX(float x) { - super.setTranslationX(x); - - if (!mProperties.isDynamicBtn) { - mProperties.x = x; - mProperties.dynamicX = Float.toString(x / CallbackBridge.physicalWidth) + " * ${screen_width}"; - setModified(true); - } - } - - @Override - public void setTranslationY(float y) { - super.setTranslationY(y); - - if (!mProperties.isDynamicBtn) { - mProperties.y = y; - mProperties.dynamicY = Float.toString(y / CallbackBridge.physicalHeight) + " * ${screen_height}"; - setModified(true); - } - } - - public void updateProperties() { - setProperties(mProperties); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (mChecked) { - canvas.drawRect(0, getHeight() - 10 * mScaleAt, getWidth(), getHeight(), mRectPaint); - } - } - - @Override - public boolean onLongClick(View p1) { - if (mCanTriggerLongClick && mModifiable) { - if (mHandleView.isShowing()) { - mHandleView.hide(); - } else { - if (getParent() != null) { - ((ControlLayout) getParent()).hideAllHandleViews(); - } - - try { - mHandleView.show(); - } catch (Throwable th) { - th.printStackTrace(); - } - } - } - - return mCanTriggerLongClick; - } - - private void setHolding(boolean isDown) { - if (mProperties.holdAlt) { - CallbackBridge.holdingAlt = isDown; - MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT,0,isDown); - System.out.println("holdingAlt="+CallbackBridge.holdingAlt); - } if (mProperties.keycode == LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK) { - CallbackBridge.holdingCapslock = isDown; - //MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK,0,isDown); - System.out.println("holdingCapslock="+CallbackBridge.holdingCapslock); - } if (mProperties.holdCtrl) { - CallbackBridge.holdingCtrl = isDown; - MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL,0,isDown); - System.out.println("holdingCtrl="+CallbackBridge.holdingCtrl); - } if (mProperties.keycode == LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK) { - CallbackBridge.holdingNumlock = isDown; - //MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK,0,isDown); - System.out.println("holdingNumlock="+CallbackBridge.holdingNumlock); - } if (mProperties.holdShift) { - CallbackBridge.holdingShift = isDown; - MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT,0,isDown); - System.out.println("holdingShift="+CallbackBridge.holdingShift); - } - } - - private float moveX, moveY; - private float downX, downY; - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!mModifiable) { - mCanTriggerLongClick = false; - if(event.getAction() == MotionEvent.ACTION_MOVE && CallbackBridge.isGrabbing() && mProperties.passThruEnabled) { - MinecraftGLView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view); - if(v != null) { - v.dispatchTouchEvent(event); - return true; - } - } - if (mProperties.keycode >= 0) { - if (!mProperties.isToggle) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: // 0 - case MotionEvent.ACTION_POINTER_DOWN: // 5 - setHolding(true); - MainActivity.sendKeyPress(mProperties.keycode, CallbackBridge.getCurrentMods(), true); - break; - case MotionEvent.ACTION_UP: // 1 - case MotionEvent.ACTION_CANCEL: // 3 - case MotionEvent.ACTION_POINTER_UP: // 6 - setHolding(false); - MainActivity.sendKeyPress(mProperties.keycode, CallbackBridge.getCurrentMods(), false); - break; - default: - return false; - } - - } else if (mGestureDetector.onTouchEvent(event)) { - mChecked = !mChecked; - invalidate(); - setHolding(mChecked); - MainActivity.sendKeyPress(mProperties.keycode, CallbackBridge.getCurrentMods(), mChecked); - } - return true; - } - } else { - if (mGestureDetector.onTouchEvent(event)) { - mCanTriggerLongClick = true; - onLongClick(this); - } - - switch (event.getActionMasked()) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_DOWN: - mCanTriggerLongClick = true; - downX = event.getX(); - downY = event.getY(); - break; - - case MotionEvent.ACTION_MOVE: - mCanTriggerLongClick = false; - moveX += event.getX() - downX; - moveY += event.getY() - downY; - - if (!mProperties.isDynamicBtn) { - setTranslationX(moveX); - setTranslationY(moveY); - } - - break; - } - } - - return super.onTouchEvent(event); - } - - public void setModifiable(boolean z) { - mModifiable = z; - } - - private void setModified(boolean modified) { - if (getParent() != null) { - ((ControlLayout) getParent()).setModified(modified); - } - } -} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java index bd3963309..6059ce2df 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java @@ -7,14 +7,11 @@ import net.kdt.pojavlaunch.utils.*; import net.objecthunter.exp4j.*; import org.lwjgl.glfw.*; +import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN; + public class ControlData implements Cloneable { - /* - public static int pixelOf2dp = (int) Tools.dpToPx(2); - public static int pixelOf30dp = (int) Tools.dpToPx(30); - public static int pixelOf50dp = Tools.dpToPx(50);; - public static int pixelOf80dp; - */ + public static final int SPECIALBTN_KEYBOARD = -1; public static final int SPECIALBTN_TOGGLECTRL = -2; public static final int SPECIALBTN_MOUSEPRI = -3; @@ -38,22 +35,21 @@ public class ControlData implements Cloneable * bigger device or vice versa. */ public String dynamicX, dynamicY; - public boolean isDynamicBtn, isToggle, passThruEnabled, isRound; + public boolean isDynamicBtn, isToggle, passThruEnabled; public static ControlData[] getSpecialButtons(){ if (SPECIAL_BUTTONS == null) { - ControlData[] specialButtons = new ControlData[]{ - new ControlData("Keyboard", SPECIALBTN_KEYBOARD, "${margin} * 3 + ${width} * 2", "${margin}", false), - new ControlData("GUI", SPECIALBTN_TOGGLECTRL, "${margin}", "${bottom} - ${margin}"), - new ControlData("PRI", SPECIALBTN_MOUSEPRI, "${margin}", "${screen_height} - ${margin} * 3 - ${height} * 3"), - new ControlData("SEC", SPECIALBTN_MOUSESEC, "${margin} * 3 + ${width} * 2", "${screen_height} - ${margin} * 3 - ${height} * 3"), - new ControlData("Mouse", SPECIALBTN_VIRTUALMOUSE, "${right}", "${margin}", false), + SPECIAL_BUTTONS = new ControlData[]{ + new ControlData("Keyboard", new int[]{SPECIALBTN_KEYBOARD}, "${margin} * 3 + ${width} * 2", "${margin}", false), + new ControlData("GUI", new int[]{SPECIALBTN_TOGGLECTRL}, "${margin}", "${bottom} - ${margin}"), + new ControlData("PRI", new int[]{SPECIALBTN_MOUSEPRI}, "${margin}", "${screen_height} - ${margin} * 3 - ${height} * 3"), + new ControlData("SEC", new int[]{SPECIALBTN_MOUSESEC}, "${margin} * 3 + ${width} * 2", "${screen_height} - ${margin} * 3 - ${height} * 3"), + new ControlData("Mouse", new int[]{SPECIALBTN_VIRTUALMOUSE}, "${right}", "${margin}", false), - new ControlData("MID", SPECIALBTN_MOUSEMID, "${margin}", "${margin}"), - new ControlData("SCROLLUP", SPECIALBTN_SCROLLUP, "${margin}", "${margin}"), - new ControlData("SCROLLDOWN", SPECIALBTN_SCROLLDOWN, "${margin}", "${margin}") + new ControlData("MID", new int[]{SPECIALBTN_MOUSEMID}, "${margin}", "${margin}"), + new ControlData("SCROLLUP", new int[]{SPECIALBTN_SCROLLUP}, "${margin}", "${margin}"), + new ControlData("SCROLLDOWN", new int[]{SPECIALBTN_SCROLLDOWN}, "${margin}", "${margin}") }; - SPECIAL_BUTTONS = specialButtons; } return SPECIAL_BUTTONS; @@ -74,76 +70,89 @@ public class ControlData implements Cloneable public String name; public float x; public float y; - public float width; - public float height; - public int keycode; - public int transparency; - @Deprecated - public boolean hidden; - public boolean holdCtrl; - public boolean holdAlt; - public boolean holdShift; + private float width; //Dp instead of Px now + private float height; //Dp instead of Px now + public int[] keycodes; //Should store up to 4 keys + public float opacity; //Alpha value from 0 to 1; + public int bgColor; + public int strokeColor; + public int strokeWidth; //0-100% + public float cornerRadius; //0-100% + public boolean isSwipeable; + public Object specialButtonListener; public ControlData() { - this("", LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, 0, 0); + this("button"); } - public ControlData(String name, int keycode) { - this(name, keycode, 0, 0); + public ControlData(String name){ + this(name, new int[] {}); } - public ControlData(String name, int keycode, float x, float y) { - this(name, keycode, x, y, Tools.dpToPx(50), Tools.dpToPx(50)); + public ControlData(String name, int[] keycodes) { + this(name, keycodes, Tools.currentDisplayMetrics.widthPixels/2, Tools.currentDisplayMetrics.heightPixels/2); } - public ControlData(android.content.Context ctx, int resId, int keycode, float x, float y, boolean isSquare) { - this(ctx.getResources().getString(resId), keycode, x, y, isSquare); + public ControlData(String name, int[] keycodes, float x, float y) { + this(name, keycodes, x, y, 50, 50); } - public ControlData(String name, int keycode, float x, float y, boolean isSquare) { - this(name, keycode, x, y, isSquare ? Tools.dpToPx(50) : Tools.dpToPx(80), isSquare ? Tools.dpToPx(50) : Tools.dpToPx(30)); + public ControlData(android.content.Context ctx, int resId, int[] keycodes, float x, float y, boolean isSquare) { + this(ctx.getResources().getString(resId), keycodes, x, y, isSquare); } - public ControlData(String name, int keycode, float x, float y, float width, float height) { - this(name, keycode, Float.toString(x), Float.toString(y), width, height, false); + public ControlData(String name, int[] keycodes, float x, float y, boolean isSquare) { + this(name, keycodes, x, y, isSquare ? 50 : 80, isSquare ? 50 : 30); + } + + public ControlData(String name, int[] keycodes, float x, float y, float width, float height) { + this(name, keycodes, Float.toString(x), Float.toString(y), width, height, false); this.isDynamicBtn = false; } - public ControlData(String name, int keycode, String dynamicX, String dynamicY) { - this(name, keycode, dynamicX, dynamicY, Tools.dpToPx(50), Tools.dpToPx(50), false); + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY) { + this(name, keycodes, dynamicX, dynamicY, 50, 50, false); } - public ControlData(android.content.Context ctx, int resId, int keycode, String dynamicX, String dynamicY, boolean isSquare) { - this(ctx.getResources().getString(resId), keycode, dynamicX, dynamicY, isSquare); + public ControlData(android.content.Context ctx, int resId, int[] keycodes, String dynamicX, String dynamicY, boolean isSquare) { + this(ctx.getResources().getString(resId), keycodes, dynamicX, dynamicY, isSquare); } - public ControlData(String name, int keycode, String dynamicX, String dynamicY, boolean isSquare) { - this(name, keycode, dynamicX, dynamicY, isSquare ? Tools.dpToPx(50) : Tools.dpToPx(80), isSquare ? Tools.dpToPx(50) : Tools.dpToPx(30), false); + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, boolean isSquare) { + this(name, keycodes, dynamicX, dynamicY, isSquare ? 50 : 80, isSquare ? 50 : 30, false); } - public ControlData(String name, int keycode, String dynamicX, String dynamicY, float width, float height, boolean isToggle) { + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle){ + this(name, keycodes, dynamicX, dynamicY, width, height, isToggle, 1,0x4D000000, 0xFFFFFFFF,0,0); + } + + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle, float opacity, int bgColor, int strokeColor, int strokeWidth, float cornerRadius) { this.name = name; - this.keycode = keycode; + this.keycodes = inflateKeycodeArray(keycodes); this.dynamicX = dynamicX; this.dynamicY = dynamicY; this.width = width; this.height = height; this.isDynamicBtn = true; this.isToggle = isToggle; + this.opacity = opacity; + this.bgColor = bgColor; + this.strokeColor = strokeColor; + this.strokeWidth = strokeWidth; + this.cornerRadius = cornerRadius; update(); } - public void execute(BaseMainActivity act, boolean isDown) { - act.sendKeyPress(keycode, 0, isDown); + public void execute(boolean isDown) { + for(int keycode : keycodes){ + BaseMainActivity.sendKeyPress(keycode, 0, isDown); + } } + public ControlData clone() { - if (this instanceof ControlData) { - return new ControlData(name, keycode, ((ControlData) this).dynamicX, ((ControlData) this).dynamicY, width, height, isToggle); - } else { - return new ControlData(name, keycode, x, y, width, height); - } + return new ControlData(name, keycodes, dynamicX, dynamicY, width, height, isToggle, opacity, bgColor, strokeColor,strokeWidth, cornerRadius); } public float insertDynamicPos(String dynamicPos) { @@ -151,10 +160,10 @@ public class ControlData implements Cloneable Map keyValueMap = new ArrayMap<>(); keyValueMap.put("top", "0"); keyValueMap.put("left", "0"); - keyValueMap.put("right", Float.toString(CallbackBridge.physicalWidth - width)); - keyValueMap.put("bottom", Float.toString(CallbackBridge.physicalHeight - height)); - keyValueMap.put("width", Float.toString(width)); - keyValueMap.put("height", Float.toString(height)); + keyValueMap.put("right", Float.toString(CallbackBridge.physicalWidth - getWidth())); + keyValueMap.put("bottom", Float.toString(CallbackBridge.physicalHeight - getHeight())); + keyValueMap.put("width", Float.toString(getWidth())); + keyValueMap.put("height", Float.toString(getHeight())); keyValueMap.put("screen_width", Integer.toString(CallbackBridge.physicalWidth)); keyValueMap.put("screen_height", Integer.toString(CallbackBridge.physicalHeight)); keyValueMap.put("margin", Integer.toString((int) Tools.dpToPx(2))); @@ -167,15 +176,17 @@ public class ControlData implements Cloneable } public void update() { - if (keycode < 0 && SPECIAL_BUTTONS != null) { - for (ControlData data : getSpecialButtons()) { - if (keycode == data.keycode) { - specialButtonListener = data.specialButtonListener; - } - } - } if (dynamicX == null) { + if(SPECIAL_BUTTONS != null) + for(int keycode : keycodes) + for (ControlData data : getSpecialButtons()) + if (keycode == data.keycodes[0]) + specialButtonListener = data.specialButtonListener; + + + if (dynamicX == null) { dynamicX = Float.toString(x); - } if (dynamicY == null) { + } + if (dynamicY == null) { dynamicY = Float.toString(y); } @@ -186,4 +197,37 @@ public class ControlData implements Cloneable private static float calculate(String math) { return (float) new ExpressionBuilder(math).build().evaluate(); } + + private static int[] inflateKeycodeArray(int[] keycodes){ + int[] inflatedArray = new int[]{GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN}; + System.arraycopy(keycodes, 0, inflatedArray, 0, keycodes.length); + return inflatedArray; + } + + + public boolean containsKeycode(int keycodeToCheck){ + for(int keycode : keycodes) + if(keycodeToCheck == keycode) + return true; + + return false; + } + + //Getters || setters (with conversion for ease of use) + public float getWidth() { + return Tools.dpToPx(width); + } + + public float getHeight(){ + return Tools.dpToPx(height); + } + + + public void setWidth(float widthInPx){ + width = Tools.pxToDp(widthInPx); + } + + public void setHeight(float heightInPx){ + height = Tools.pxToDp(heightInPx); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java new file mode 100644 index 000000000..cdb02339c --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java @@ -0,0 +1,76 @@ +package net.kdt.pojavlaunch.customcontrols; + +import net.kdt.pojavlaunch.Tools; + +import java.util.ArrayList; + +import static net.kdt.pojavlaunch.customcontrols.ControlDrawerData.Orientation.DOWN; +import static net.kdt.pojavlaunch.customcontrols.ControlDrawerData.Orientation.LEFT; +import static net.kdt.pojavlaunch.customcontrols.ControlDrawerData.Orientation.RIGHT; +import static net.kdt.pojavlaunch.customcontrols.ControlDrawerData.Orientation.UP; + +public class ControlDrawerData { + + public ArrayList buttonProperties; + public ControlData properties; + public Orientation orientation; + + public enum Orientation { + DOWN, + LEFT, + UP, + RIGHT + } + + public static Orientation[] getOrientations(){ + return new Orientation[]{DOWN,LEFT,UP,RIGHT}; + } + + public static int orientationToInt(Orientation orientation){ + switch (orientation){ + case DOWN: + return 0; + case LEFT: + return 1; + case UP: + return 2; + case RIGHT: + return 3; + } + return -1; + } + + public static Orientation intToOrientation(int by){ + switch (by){ + case 0: + return Orientation.DOWN; + case 1: + return Orientation.LEFT; + case 2: + return Orientation.UP; + case 3: + return RIGHT; + } + return null; + } + + public ControlDrawerData(){ + this(new ArrayList<>()); + } + + public ControlDrawerData(ArrayList buttonProperties){ + this(buttonProperties, new ControlData("Drawer", new int[] {}, Tools.currentDisplayMetrics.widthPixels/2, Tools.currentDisplayMetrics.heightPixels/2)); + } + + public ControlDrawerData(ArrayList buttonProperties, ControlData properties){ + this(buttonProperties, properties, Orientation.LEFT); + } + + + public ControlDrawerData(ArrayList buttonProperties, ControlData properties, Orientation orientation){ + this.buttonProperties = buttonProperties; + this.properties = properties; + this.orientation = orientation; + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java index cc5dac562..6cf5456fb 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java @@ -6,10 +6,19 @@ import android.widget.*; import com.google.gson.*; import java.io.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import net.kdt.pojavlaunch.*; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton; +import net.kdt.pojavlaunch.customcontrols.handleview.HandleView; import net.kdt.pojavlaunch.prefs.*; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.lwjgl.glfw.*; public class ControlLayout extends FrameLayout @@ -28,59 +37,62 @@ public class ControlLayout extends FrameLayout } public void hideAllHandleViews() { - for (int i = 0; i < getChildCount(); i++) { - View view = getChildAt(i); - if (view instanceof ControlButton) { - ((ControlButton) view).getHandleView().hide(); - } + for(ControlButton button : getButtonChildren()){ + HandleView hv = button.getHandleView(); + if(hv != null) hv.hide(); } } public void loadLayout(String jsonPath) throws IOException, JsonSyntaxException { - loadLayout(Tools.GLOBAL_GSON.fromJson(Tools.read(jsonPath), CustomControls.class)); + CustomControls layout = LayoutConverter.loadAndConvertIfNecessary(jsonPath); + if(layout != null) { + loadLayout(layout); + }else{ + throw new IOException("Unsupported control layout version"); + } } public void loadLayout(CustomControls controlLayout) { - if (mModifiable) { + if (mModifiable) hideAllHandleViews(); - } - /*if (getChildAt(0) instanceof MinecraftGLView) { - View viewGL = getChildAt(0); - View viewTouchpad = getChildAt(1); - removeAllViews(); - addView(viewGL); - addView(viewTouchpad); - } else { - removeAllViews();*/ - removeAllButtons(); - //} - if (mLayout != null) { - mLayout.mControlDataList = null; - mLayout = null; - } + + removeAllButtons(); + if(mLayout != null) { + mLayout.mControlDataList = null; + mLayout = null; + } + System.gc(); + mapTable.clear(); // Cleanup buttons only when input layout is null if (controlLayout == null) return; mLayout = controlLayout; - + + //CONTROL BUTTON for (ControlData button : controlLayout.mControlDataList) { - button.isHideable = button.keycode != ControlData.SPECIALBTN_TOGGLECTRL && button.keycode != ControlData.SPECIALBTN_VIRTUALMOUSE; - button.width = button.width / controlLayout.scaledAt * LauncherPreferences.PREF_BUTTONSIZE; - button.height = button.height / controlLayout.scaledAt * LauncherPreferences.PREF_BUTTONSIZE; - if (!button.isDynamicBtn) { - button.dynamicX = Float.toString(button.x / CallbackBridge.physicalWidth) + " * ${screen_width}"; - button.dynamicY = Float.toString(button.y / CallbackBridge.physicalHeight) + " * ${screen_height}"; - } - button.update(); addControlView(button); } + + //CONTROL DRAWER + for(ControlDrawerData drawerData : controlLayout.mDrawerDataList){ + ControlDrawer drawer = addDrawerView(drawerData); + if(mModifiable) drawer.areButtonsVisible = true; + + + //CONTROL SUB BUTTON + for (ControlData subButton : drawerData.buttonProperties) { + addSubView(drawer, subButton); + } + } + mLayout.scaledAt = LauncherPreferences.PREF_BUTTONSIZE; setModified(false); - } + } // loadLayout + //CONTROL BUTTON public void addControlButton(ControlData controlButton) { mLayout.mControlDataList.add(controlButton); addControlView(controlButton); @@ -90,7 +102,7 @@ public class ControlLayout extends FrameLayout final ControlButton view = new ControlButton(this, controlButton); view.setModifiable(mModifiable); if (!mModifiable) { - view.setAlpha(1f - view.getProperties().transparency / 100f); + view.setAlpha(view.getProperties().opacity); view.setFocusable(false); view.setFocusableInTouchMode(false); } @@ -98,22 +110,63 @@ public class ControlLayout extends FrameLayout setModified(true); } + + // CONTROL DRAWER + public void addDrawer(ControlDrawerData drawerData){ + mLayout.mDrawerDataList.add(drawerData); + addDrawerView(); + } + + private void addDrawerView(){ + addDrawerView(null); + } + + private ControlDrawer addDrawerView(ControlDrawerData drawerData){ + + final ControlDrawer view = new ControlDrawer(this,drawerData == null ? mLayout.mDrawerDataList.get(mLayout.mDrawerDataList.size()-1) : drawerData); + view.setModifiable(mModifiable); + if (!mModifiable) { + view.setAlpha(view.getProperties().opacity); + view.setFocusable(false); + view.setFocusableInTouchMode(false); + } + addView(view); + + setModified(true); + return view; + } + + //CONTROL SUB-BUTTON + public void addSubButton(ControlDrawer drawer, ControlData controlButton){ + //Yep there isn't much here + drawer.getDrawerData().buttonProperties.add(controlButton); + addSubView(drawer, drawer.getDrawerData().buttonProperties.get(drawer.getDrawerData().buttonProperties.size()-1 )); + } + + public void addSubView(ControlDrawer drawer, ControlData controlButton){ + final ControlSubButton view = new ControlSubButton(this, controlButton, drawer); + view.setModifiable(mModifiable); + if (!mModifiable) { + view.setAlpha(view.getProperties().opacity); + view.setFocusable(false); + view.setFocusableInTouchMode(false); + } + drawer.addButton(view); + addView(view); + + setModified(true); + } + private void removeAllButtons() { - List viewList = new ArrayList<>(); - View v; - for(int i = 0; i < getChildCount(); i++) { - v = getChildAt(i); - if(v instanceof ControlButton) viewList.add(v); + for(View v : getButtonChildren()){ + removeView(v); } - v = null; - for(View v2 : viewList) { - removeView(v2); - } - viewList = null; + System.gc(); //i wanna be sure that all the removed Views will be removed after a reload //because if frames will slowly go down after many control changes it will be warm and bad } + public void removeControlButton(ControlButton controlButton) { mLayout.mControlDataList.remove(controlButton.getProperties()); controlButton.setVisibility(View.GONE); @@ -122,6 +175,22 @@ public class ControlLayout extends FrameLayout setModified(true); } + public void removeControlDrawer(ControlDrawer controlDrawer){ + mLayout.mDrawerDataList.remove(controlDrawer.getDrawerData()); + controlDrawer.setVisibility(GONE); + removeView(controlDrawer); + + setModified(true); + } + + public void removeControlSubButton(ControlSubButton subButton){ + subButton.parentDrawer.drawerData.buttonProperties.remove(subButton.getProperties()); + subButton.parentDrawer.buttons.remove(subButton); + + subButton.setVisibility(GONE); + removeView(subButton); + } + public void saveLayout(String path) throws Exception { mLayout.save(path); setModified(false); @@ -130,34 +199,97 @@ public class ControlLayout extends FrameLayout public void setActivity(CustomControlsActivity activity) { mActivity = activity; } - - public void toggleControlVisible() { - if (mModifiable) return; // Not using on custom controls activity - + + public void toggleControlVisible(){ mControlVisible = !mControlVisible; - for (int i = 0; i < getChildCount(); i++) { - View view = getChildAt(i); - if (view instanceof ControlButton && ((ControlButton) view).getProperties().isHideable) { - ((ControlButton) view).setVisibility(mControlVisible ? View.VISIBLE : View.GONE); - } + setControlVisible(mControlVisible); + } + + public float getLayoutScale(){ + return mLayout.scaledAt; + } + + public void setControlVisible(boolean isVisible) { + if (mModifiable) return; // Not using on custom controls activity + + mControlVisible = isVisible; + for(ControlButton button : getButtonChildren()){ + button.setVisible(isVisible); } } - public void setModifiable(boolean z) { - mModifiable = z; - for (int i = 0; i < getChildCount(); i++) { - View v = getChildAt(i); - if (v instanceof ControlButton) { - ControlButton cv = ((ControlButton) v); - cv.setModifiable(z); - if (!z) { - cv.setAlpha(1f - cv.getProperties().transparency / 100f); - } - } + public void setModifiable(boolean isModifiable) { + mModifiable = isModifiable; + for(ControlButton button : getButtonChildren()){ + button.setModifiable(isModifiable); + if (!isModifiable) + button.setAlpha(button.getProperties().opacity); } } - protected void setModified(boolean z) { - if (mActivity != null) mActivity.isModified = z; + public boolean getModifiable(){ + return mModifiable; + } + + public void setModified(boolean isModified) { + if (mActivity != null) mActivity.isModified = isModified; + + } + + private ArrayList getButtonChildren(){ + ArrayList children = new ArrayList<>(); + for(int i=0; i mapTable = new HashMap<>(); + //While this is called onTouch, this should only be called from a ControlButton. + public boolean onTouch(View v, MotionEvent ev) { + ControlButton lastControlButton = mapTable.get(v); + + //Check if the action is cancelling, reset the lastControl button associated to the view + if(ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_CANCEL){ + if(lastControlButton != null) lastControlButton.onTouchEvent(ev); + mapTable.put(v, null); + return true; + } + + if(ev.getActionMasked() != MotionEvent.ACTION_MOVE) return false; + + //Optimization pass to avoid looking at all children again + if(lastControlButton != null){ + if( ev.getRawX() > lastControlButton.getX() && ev.getRawX() < lastControlButton.getX() + lastControlButton.getWidth() && + ev.getRawY() > lastControlButton.getY() && ev.getRawY() < lastControlButton.getY() + lastControlButton.getHeight()){ + return true; + } + } + + //Release the last key + ev.setAction(MotionEvent.ACTION_POINTER_UP); + if (lastControlButton != null) lastControlButton.onTouchEvent(ev); + mapTable.put(v, null); + + //Look for another SWIPEABLE button + for(ControlButton button : getButtonChildren()){ + if(!button.getProperties().isSwipeable) continue; + + if( ev.getRawX() > button.getX() && ev.getRawX() < button.getX() + button.getWidth() && + ev.getRawY() > button.getY() && ev.getRawY() < button.getY() + button.getHeight()){ + + //Press the new key + if(!button.equals(lastControlButton)){ + ev.setAction(MotionEvent.ACTION_POINTER_DOWN); + button.onTouchEvent(ev); + + mapTable.put(v, button); + } + return true; + } + } + return false; } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java index 43c67ad24..2851e987b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java @@ -1,20 +1,26 @@ package net.kdt.pojavlaunch.customcontrols; import android.content.*; import com.google.gson.*; + +import java.io.IOException; import java.util.*; import net.kdt.pojavlaunch.*; import org.lwjgl.glfw.*; -public class CustomControls -{ +public class CustomControls { + public int version = -1; public float scaledAt; public List mControlDataList; + public List mDrawerDataList; public CustomControls() { - this(new ArrayList()); + this(new ArrayList<>(), new ArrayList<>()); } - - public CustomControls(List mControlDataList) { + + + + public CustomControls(List mControlDataList, List mDrawerDataList) { this.mControlDataList = mControlDataList; + this.mDrawerDataList = mDrawerDataList; this.scaledAt = 100f; } @@ -27,35 +33,42 @@ public class CustomControls this.mControlDataList.add(ControlData.getSpecialButtons()[3].clone()); // Secondary Mouse mControlDataList this.mControlDataList.add(ControlData.getSpecialButtons()[4].clone()); // Virtual mouse toggle - this.mControlDataList.add(new ControlData(ctx, R.string.control_debug, LWJGLGLFWKeycode.GLFW_KEY_F3, "${margin}", "${margin}", false)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_chat, LWJGLGLFWKeycode.GLFW_KEY_T, "${margin} * 2 + ${width}", "${margin}", false)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_listplayers, LWJGLGLFWKeycode.GLFW_KEY_TAB, "${margin} * 4 + ${width} * 3", "${margin}", false)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_thirdperson, LWJGLGLFWKeycode.GLFW_KEY_F5, "${margin}", "${height} + ${margin}", false)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_debug, new int[]{LWJGLGLFWKeycode.GLFW_KEY_F3}, "${margin}", "${margin}", false)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_chat, new int[]{LWJGLGLFWKeycode.GLFW_KEY_T}, "${margin} * 2 + ${width}", "${margin}", false)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_listplayers, new int[]{LWJGLGLFWKeycode.GLFW_KEY_TAB}, "${margin} * 4 + ${width} * 3", "${margin}", false)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_thirdperson, new int[]{LWJGLGLFWKeycode.GLFW_KEY_F5}, "${margin}", "${height} + ${margin}", false)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_up, LWJGLGLFWKeycode.GLFW_KEY_W, "${margin} * 2 + ${width}", "${bottom} - ${margin} * 3 - ${height} * 2", true)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_left, LWJGLGLFWKeycode.GLFW_KEY_A, "${margin}", "${bottom} - ${margin} * 2 - ${height}", true)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_down, LWJGLGLFWKeycode.GLFW_KEY_S, "${margin} * 2 + ${width}", "${bottom} - ${margin}", true)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_right, LWJGLGLFWKeycode.GLFW_KEY_D, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin} * 2 - ${height}", true)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_up, new int[]{LWJGLGLFWKeycode.GLFW_KEY_W}, "${margin} * 2 + ${width}", "${bottom} - ${margin} * 3 - ${height} * 2", true)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_left, new int[]{LWJGLGLFWKeycode.GLFW_KEY_A}, "${margin}", "${bottom} - ${margin} * 2 - ${height}", true)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_down, new int[]{LWJGLGLFWKeycode.GLFW_KEY_S}, "${margin} * 2 + ${width}", "${bottom} - ${margin}", true)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_right, new int[]{LWJGLGLFWKeycode.GLFW_KEY_D}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin} * 2 - ${height}", true)); - this.mControlDataList.add(new ControlData(ctx, R.string.control_inventory, LWJGLGLFWKeycode.GLFW_KEY_E, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin}", true)); + this.mControlDataList.add(new ControlData(ctx, R.string.control_inventory, new int[]{LWJGLGLFWKeycode.GLFW_KEY_E}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin}", true)); - ControlData shiftData = new ControlData(ctx, R.string.control_shift, LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT, "${margin} * 2 + ${width}", "${screen_height} - ${margin} * 2 - ${height} * 2", true); + ControlData shiftData = new ControlData(ctx, R.string.control_shift, new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT}, "${margin} * 2 + ${width}", "${screen_height} - ${margin} * 2 - ${height} * 2", true); shiftData.isToggle = true; this.mControlDataList.add(shiftData); - this.mControlDataList.add(new ControlData(ctx, R.string.control_jump, LWJGLGLFWKeycode.GLFW_KEY_SPACE, "${right} - ${margin} * 2 - ${width}", "${bottom} - ${margin} * 2 - ${height}", true)); - + this.mControlDataList.add(new ControlData(ctx, R.string.control_jump, new int[]{LWJGLGLFWKeycode.GLFW_KEY_SPACE}, "${right} - ${margin} * 2 - ${width}", "${bottom} - ${margin} * 2 - ${height}", true)); + + //The default controls are conform to the V2 + version = 2; } public ControlData findControlData(int keycode) { for (ControlData data : mControlDataList) { - if (data.keycode == keycode) { - return data; - } + for(int dataKeycode : data.keycodes){ + if (dataKeycode == keycode) { + return data; + } + } } return null; } - public void save(String path) throws Exception { + public void save(String path) throws IOException { + //Current version is the V2 so the version as to be marked as 2 ! + version = 2; + Tools.write(path, Tools.GLOBAL_GSON.toJson(this)); } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java new file mode 100644 index 000000000..002735587 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java @@ -0,0 +1,77 @@ +package net.kdt.pojavlaunch.customcontrols; + +import com.google.gson.JsonSyntaxException; + +import net.kdt.pojavlaunch.LWJGLGLFWKeycode; +import net.kdt.pojavlaunch.Tools; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; + +public class LayoutConverter { + public static boolean convertLookType = false; //false = flat; true = classic + public static CustomControls loadAndConvertIfNecessary(String jsonPath) throws IOException, JsonSyntaxException { + String jsonLayoutData = Tools.read(jsonPath); + try { + JSONObject layoutJobj = new JSONObject(jsonLayoutData); + + if(!layoutJobj.has("version")) { //v1 layout + CustomControls layout = LayoutConverter.convertV1Layout(layoutJobj); + layout.save(jsonPath); + return layout; + }else if (layoutJobj.getInt("version") == 2) { + return Tools.GLOBAL_GSON.fromJson(jsonLayoutData, CustomControls.class); + }else{ + return null; + } + }catch (JSONException e) { + throw new JsonSyntaxException("Failed to load",e); + } + } + public static CustomControls convertV1Layout(JSONObject oldLayoutJson) throws JSONException { + CustomControls empty = new CustomControls(); + JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList"); + for(int i = 0; i < layoutMainArray.length(); i++) { + JSONObject button = layoutMainArray.getJSONObject(i); + ControlData n_button = new ControlData(); + int[] keycodes = new int[] {LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, + LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, + LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN, + LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN}; + n_button.dynamicX = button.getString("dynamicX"); + n_button.dynamicY = button.getString("dynamicY"); + n_button.isDynamicBtn = button.getBoolean("isDynamicBtn"); + n_button.name = button.getString("name"); + n_button.opacity = ((float)((button.getInt("transparency")-100)*-1))/100f; + n_button.passThruEnabled = button.getBoolean("passThruEnabled"); + n_button.isToggle = button.getBoolean("isToggle"); + n_button.x = button.getInt("x"); + n_button.y = button.getInt("y"); + n_button.setHeight(button.getInt("height")); + n_button.setWidth(button.getInt("width")); + if(convertLookType) { + n_button.strokeColor = 0xdd7f7f7f; + n_button.bgColor = 0x807f7f7f; + n_button.strokeWidth = 10; + }else{ + n_button.bgColor = 0x4d000000; + n_button.strokeWidth = 0; + } + if(button.getBoolean("isRound")) { n_button.cornerRadius = 35f; } + int next_idx = 0; + if(button.getBoolean("holdShift")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT; next_idx++; } + if(button.getBoolean("holdCtrl")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL; next_idx++; } + if(button.getBoolean("holdAlt")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT; next_idx++; } + keycodes[next_idx] = button.getInt("keycode"); + n_button.keycodes = keycodes; + n_button.update(); + empty.mControlDataList.add(n_button); + } + empty.scaledAt = (float)oldLayoutJson.getDouble("scaledAt"); + empty.version = 2; + return empty; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java new file mode 100644 index 000000000..1f4ca2d64 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java @@ -0,0 +1,341 @@ +package net.kdt.pojavlaunch.customcontrols.buttons; + +import android.annotation.SuppressLint; +import android.graphics.*; +import android.graphics.drawable.GradientDrawable; +import android.util.*; +import android.view.*; +import android.view.View.*; +import android.widget.*; + +import net.kdt.pojavlaunch.customcontrols.ControlData; +import net.kdt.pojavlaunch.customcontrols.ControlLayout; +import net.kdt.pojavlaunch.customcontrols.handleview.*; +import net.kdt.pojavlaunch.*; +import net.kdt.pojavlaunch.prefs.LauncherPreferences; + +import org.lwjgl.glfw.*; + +import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN; + +@SuppressLint("ViewConstructor") +public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener +{ + private Paint mRectPaint; + + protected GestureDetector mGestureDetector; + protected ControlData mProperties; + protected SelectionEndHandleView mHandleView; + + protected boolean mModifiable = false; + protected boolean mCanTriggerLongClick = true; + + protected boolean isToggled = false; + protected boolean isPointerOutOfBounds = false; + + public ControlButton(ControlLayout layout, ControlData properties) { + super(layout.getContext()); + setPadding(4, 4, 4, 4); + + setOnLongClickListener(this); + + //When a button is created, the width/height has yet to be processed to fit the scaling. + setProperties(preProcessProperties(properties, layout)); + setModified(false); + + + //For the toggle layer + final TypedValue value = new TypedValue(); + getContext().getTheme().resolveAttribute(R.attr.colorAccent, value, true); + + mRectPaint = new Paint(); + mRectPaint.setColor(value.data); + mRectPaint.setAlpha(128); + } + + public HandleView getHandleView() { + return mHandleView; + } + + public ControlData getProperties() { + return mProperties; + } + + public void setProperties(ControlData properties) { + setProperties(properties, true); + } + + public ControlData preProcessProperties(ControlData properties, ControlLayout layout){ + //When a button is created, properties have to be modified to fit the screen. + //Size + properties.setWidth(properties.getWidth() / layout.getLayoutScale() * LauncherPreferences.PREF_BUTTONSIZE); + properties.setHeight(properties.getHeight() / layout.getLayoutScale() * LauncherPreferences.PREF_BUTTONSIZE); + + //Visibility + properties.isHideable = !properties.containsKeycode(ControlData.SPECIALBTN_TOGGLECTRL) && !properties.containsKeycode(ControlData.SPECIALBTN_VIRTUALMOUSE); + + //Position + if (!properties.isDynamicBtn) { + properties.dynamicX = properties.x / CallbackBridge.physicalWidth + " * ${screen_width}"; + properties.dynamicY = properties.y / CallbackBridge.physicalHeight + " * ${screen_height}"; + } + + properties.update(); + return properties; + } + + public void setProperties(ControlData properties, boolean changePos) { + mProperties = properties; + + properties.update(); + + // com.android.internal.R.string.delete + // android.R.string. + setText(properties.name); + + if (changePos) { + setX(properties.x); + setY(properties.y); + } + + if (properties.specialButtonListener == null) { + // A non-special button or inside custom controls screen so skip listener + } else if (properties.specialButtonListener instanceof View.OnClickListener) { + setOnClickListener((View.OnClickListener) properties.specialButtonListener); + // setOnLongClickListener(null); + // setOnTouchListener(null); + } else if (properties.specialButtonListener instanceof View.OnTouchListener) { + // setOnLongClickListener(null); + setOnTouchListener((View.OnTouchListener) properties.specialButtonListener); + } else { + throw new IllegalArgumentException("Field " + ControlData.class.getName() + ".specialButtonListener must be View.OnClickListener or View.OnTouchListener, but was " + + properties.specialButtonListener.getClass().getName()); + } + + setLayoutParams(new FrameLayout.LayoutParams((int) properties.getWidth(), (int) properties.getHeight() )); + } + + public void setBackground(){ + GradientDrawable gd = new GradientDrawable(); + gd.setColor(mProperties.bgColor); + gd.setStroke(computeStrokeWidth(mProperties.strokeWidth), mProperties.strokeColor); + gd.setCornerRadius(computeCornerRadius(mProperties.cornerRadius)); + + setBackground(gd); + } + + public void setModifiable(boolean isModifiable) { + mModifiable = isModifiable; + } + + private void setModified(boolean modified) { + if (getParent() != null) + ((ControlLayout) getParent()).setModified(modified); + } + + + + @Override + public void setLayoutParams(ViewGroup.LayoutParams params) { + super.setLayoutParams(params); + + mProperties.setWidth(params.width); + mProperties.setHeight(params.height); + setBackground(); + + // Re-calculate position + mProperties.update(); + setX(mProperties.x); + setY(mProperties.y); + + setModified(true); + } + + public void setVisible(boolean isVisible){ + if(mProperties.isHideable) + setVisibility(isVisible ? VISIBLE : GONE); + } + + @Override + public void setX(float x) { + super.setX(x); + + if (!mProperties.isDynamicBtn) { + mProperties.x = x; + mProperties.dynamicX = x / CallbackBridge.physicalWidth + " * ${screen_width}"; + setModified(true); + } + } + + @Override + public void setY(float y) { + super.setY(y); + + if (!mProperties.isDynamicBtn) { + mProperties.y = y; + mProperties.dynamicY = y / CallbackBridge.physicalHeight + " * ${screen_height}"; + setModified(true); + } + } + + public void updateProperties() { + setProperties(mProperties); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isToggled) + canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mProperties.cornerRadius, mProperties.cornerRadius, mRectPaint); + } + + @Override + public boolean onLongClick(View v) { + if (mCanTriggerLongClick && mModifiable) { + //Instantiate on need only + if(mHandleView == null) mHandleView = new SelectionEndHandleView(this); + + if (mHandleView.isShowing()) { + mHandleView.hide(); + } else { + if (getParent() != null) { + ((ControlLayout) getParent()).hideAllHandleViews(); + } + + try { + mHandleView.show(this); + } catch (Throwable th) { + th.printStackTrace(); + } + } + } + + return mCanTriggerLongClick; + } + + protected float downX, downY; + @Override + public boolean onTouchEvent(MotionEvent event) { + if(!mModifiable){ + mCanTriggerLongClick = false; + + switch (event.getActionMasked()){ + case MotionEvent.ACTION_MOVE: + //Send the event to be taken as a mouse action + if(mProperties.passThruEnabled && CallbackBridge.isGrabbing()){ + MinecraftGLView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view); + if (v != null) v.dispatchTouchEvent(event); + } + + //If out of bounds + if(event.getX() < getLeft() || event.getX() > getRight() || + event.getY() < getTop() || event.getY() > getBottom()){ + if(mProperties.isSwipeable && !isPointerOutOfBounds){ + //Remove keys + if(!triggerToggle(event)) { + sendKeyPresses(event, false); + } + } + isPointerOutOfBounds = true; + ((ControlLayout) getParent()).onTouch(this, event); + break; + } + + //Else if we now are in bounds + if(isPointerOutOfBounds) { + ((ControlLayout) getParent()).onTouch(this, event); + //RE-press the button + if(mProperties.isSwipeable && !mProperties.isToggle){ + sendKeyPresses(event, true); + } + } + isPointerOutOfBounds = false; + break; + + case MotionEvent.ACTION_DOWN: // 0 + case MotionEvent.ACTION_POINTER_DOWN: // 5 + if(!mProperties.isToggle){ + sendKeyPresses(event, true); + } + break; + + case MotionEvent.ACTION_UP: // 1 + case MotionEvent.ACTION_CANCEL: // 3 + case MotionEvent.ACTION_POINTER_UP: // 6 + if(isPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event); + isPointerOutOfBounds = false; + + if(!triggerToggle(event)) { + sendKeyPresses(event, false); + } + break; + + default: + return false; + } + return true; + } + + /* If the button can be modified/moved */ + //Instantiate the gesture detector only when needed + if(mGestureDetector == null) mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm()); + + if (mGestureDetector.onTouchEvent(event)) { + mCanTriggerLongClick = true; + onLongClick(this); + } + + switch (event.getActionMasked()) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_DOWN: + mCanTriggerLongClick = true; + downX = event.getRawX() - getX(); + downY = event.getRawY() - getY(); + break; + + case MotionEvent.ACTION_MOVE: + mCanTriggerLongClick = false; + + if (!mProperties.isDynamicBtn) { + setX(event.getRawX() - downX); + setY(event.getRawY() - downY); + } + break; + } + + return super.onTouchEvent(event); + } + + public int computeStrokeWidth(float widthInPercent){ + float maxSize = Math.max(mProperties.getWidth(), mProperties.getHeight()); + return (int)((maxSize/2) * (widthInPercent/100)); + } + + public float computeCornerRadius(float radiusInPercent){ + float minSize = Math.min(mProperties.getWidth(), mProperties.getHeight()); + return (minSize/2) * (radiusInPercent/100); + } + + public boolean triggerToggle(MotionEvent event){ + //returns true a the toggle system is triggered + if(mProperties.isToggle){ + isToggled = !isToggled; + invalidate(); + sendKeyPresses(event, isToggled); + return true; + } + return false; + } + + public void sendKeyPresses(MotionEvent event, boolean isDown){ + for(int keycode : mProperties.keycodes){ + if(keycode >= GLFW_KEY_UNKNOWN){ + MainActivity.sendKeyPress(keycode, CallbackBridge.getCurrentMods(), isDown); + CallbackBridge.setModifiers(keycode, isDown); + }else { + super.onTouchEvent(event); + } + } + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java new file mode 100644 index 000000000..f17f583a4 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java @@ -0,0 +1,153 @@ +package net.kdt.pojavlaunch.customcontrols.buttons; + +import android.annotation.SuppressLint; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.customcontrols.ControlData; +import net.kdt.pojavlaunch.customcontrols.ControlDrawerData; +import net.kdt.pojavlaunch.customcontrols.ControlLayout; + +import java.util.ArrayList; + + + +@SuppressLint("ViewConstructor") +public class ControlDrawer extends ControlButton { + + + public ArrayList buttons; + public ControlDrawerData drawerData; + public ControlLayout mLayout; + public boolean areButtonsVisible = false; + + + public ControlDrawer(ControlLayout layout, ControlDrawerData drawerData) { + super(layout, drawerData.properties); + + buttons = new ArrayList<>(drawerData.buttonProperties.size()); + mLayout = layout; + this.drawerData = drawerData; + } + + + public void addButton(ControlData properties){ + addButton(new ControlSubButton(mLayout, properties, this)); + } + + public void addButton(ControlSubButton button){ + buttons.add(button); + setControlButtonVisibility(button, mModifiable || areButtonsVisible); + syncButtons(); + } + + private void setControlButtonVisibility(ControlButton button, boolean isVisible){ + button.setVisible(isVisible); + } + + private void switchButtonVisibility(){ + areButtonsVisible = !areButtonsVisible; + for(ControlButton button : buttons){ + button.setVisible(areButtonsVisible); + } + } + + //Syncing stuff + private void alignButtons(){ + + if(buttons == null) return; + for(int i=0; i < buttons.size(); ++i){ + switch (drawerData.orientation){ + case RIGHT: + buttons.get(i).setX(drawerData.properties.x + (drawerData.properties.getWidth() + Tools.dpToPx(2))*(i+1) ); + buttons.get(i).setY(drawerData.properties.y); + break; + + case LEFT: + buttons.get(i).setX(drawerData.properties.x - (drawerData.properties.getWidth() + Tools.dpToPx(2))*(i+1) ); + buttons.get(i).setY(drawerData.properties.y); + break; + + case UP: + buttons.get(i).setY(drawerData.properties.y - (drawerData.properties.getHeight() + Tools.dpToPx(2))*(i+1) ); + buttons.get(i).setX(drawerData.properties.x); + break; + + case DOWN: + buttons.get(i).setY(drawerData.properties.y + (drawerData.properties.getHeight() + Tools.dpToPx(2))*(i+1) ); + buttons.get(i).setX(drawerData.properties.x); + break; + } + buttons.get(i).updateProperties(); + } + } + + + private void resizeButtons(){ + if (buttons == null) return; + for(ControlSubButton subButton : buttons){ + subButton.mProperties.setWidth(mProperties.getWidth()); + subButton.mProperties.setHeight(mProperties.getHeight()); + + subButton.updateProperties(); + } + } + + private void syncButtons(){ + alignButtons(); + resizeButtons(); + } + + @Override + public ControlData preProcessProperties(ControlData properties, ControlLayout layout) { + ControlData data = super.preProcessProperties(properties, layout); + data.isHideable = true; + return data; + } + + @Override + public void setVisible(boolean isVisible) { + //TODO replicate changes to his children ? + setVisibility(isVisible ? VISIBLE : GONE); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if(!mModifiable){ + switch (event.getActionMasked()){ + case MotionEvent.ACTION_UP: // 1 + case MotionEvent.ACTION_POINTER_UP: // 6 + switchButtonVisibility(); + break; + } + return true; + } + + return super.onTouchEvent(event); + } + + @Override + public void setX(float x) { + super.setX(x); + alignButtons(); + } + + @Override + public void setY(float y) { + super.setY(y); + alignButtons(); + } + + @Override + public void setLayoutParams(ViewGroup.LayoutParams params) { + super.setLayoutParams(params); + syncButtons(); + } + + //Getters + public ControlDrawerData getDrawerData() { + return drawerData; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java new file mode 100644 index 000000000..1692df4a3 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java @@ -0,0 +1,65 @@ +package net.kdt.pojavlaunch.customcontrols.buttons; + +import android.os.Handler; +import android.os.Looper; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import net.kdt.pojavlaunch.SingleTapConfirm; +import net.kdt.pojavlaunch.customcontrols.ControlData; +import net.kdt.pojavlaunch.customcontrols.ControlLayout; + +public class ControlSubButton extends ControlButton { + + public ControlDrawer parentDrawer; + + public ControlSubButton(ControlLayout layout, ControlData properties, ControlDrawer parentDrawer) { + super(layout, properties); + this.parentDrawer = parentDrawer; + + //Delayed to let the button inflate first + if(!layout.getModifiable()) + new Handler(Looper.getMainLooper()).postDelayed(() -> setVisibility(parentDrawer.areButtonsVisible ? VISIBLE : GONE), 0); + + filterProperties(); + } + + private void filterProperties(){ + mProperties.setHeight(parentDrawer.getProperties().getHeight()); + mProperties.setWidth(parentDrawer.getProperties().getWidth()); + mProperties.isDynamicBtn = false; + + setProperties(mProperties, false); + } + + @Override + public void setVisible(boolean isVisible) { + setVisibility(isVisible ? (parentDrawer.areButtonsVisible ? VISIBLE : GONE) : (!mProperties.isHideable && parentDrawer.getVisibility() == GONE) ? VISIBLE : View.GONE); + } + + @Override + public void setLayoutParams(ViewGroup.LayoutParams params) { + if(parentDrawer != null){ + params.width = (int)parentDrawer.mProperties.getWidth(); + params.height = (int)parentDrawer.mProperties.getHeight(); + } + super.setLayoutParams(params); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if(!mModifiable){ + return super.onTouchEvent(event); + } + + if(mGestureDetector == null) mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm()); + + if (mGestureDetector.onTouchEvent(event)) { + mCanTriggerLongClick = true; + onLongClick(this); + } + return true; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java new file mode 100644 index 000000000..e2b0f58fa --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java @@ -0,0 +1,348 @@ +package net.kdt.pojavlaunch.customcontrols.gamepad; + + +import android.os.Handler; +import android.os.Looper; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.Toast; + +import androidx.core.math.MathUtils; + +import net.kdt.pojavlaunch.BaseMainActivity; +import net.kdt.pojavlaunch.LWJGLGLFWKeycode; +import net.kdt.pojavlaunch.MainActivity; +import net.kdt.pojavlaunch.R; + +import org.lwjgl.glfw.CallbackBridge; + +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NONE; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.isJoystickEvent; + +public class Gamepad { + + private final BaseMainActivity gameActivity; + private final ImageView pointerView; + + private final GamepadDpad gamepadDpad = new GamepadDpad(); + + private final GamepadJoystick leftJoystick; + private int currentJoystickDirection = DIRECTION_NONE; + + private final GamepadJoystick rightJoystick; + private float lastHorizontalValue = 0.0f; + private float lastVerticalValue = 0.0f; + + private final double mouseMaxAcceleration = 2f; + private double acceleration = 0.0f; + + private double mouseMagnitude; + private double mouseAngle; + private double mouseSensitivity = 19; + + private final GamepadMap gameMap = GamepadMap.getDefaultGameMap(); + private final GamepadMap menuMap = GamepadMap.getDefaultMenuMap(); + private GamepadMap currentMap = gameMap; + + private boolean lastGrabbingState = true; + private final boolean hasDigitalTriggers; + + private final Handler handler = new Handler(Looper.getMainLooper()); + private final Runnable switchStateRunnable; + + public Gamepad(BaseMainActivity gameActivity, InputDevice inputDevice){ + //Toast.makeText(gameActivity.getApplicationContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show(); + + leftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice); + rightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice); + hasDigitalTriggers = inputDevice.hasKeys(KeyEvent.KEYCODE_BUTTON_R2)[0]; + + this.gameActivity = gameActivity; + pointerView = this.gameActivity.findViewById(R.id.console_pointer); + pointerView.getDrawable().setFilterBitmap(false); + notifyGUISizeChange(gameActivity.getMcScale()); + + Runnable handlerRunnable = new Runnable() { + + @Override + public void run() { + updateGrabbingState(); + tick(); + + handler.postDelayed(this, 16); + } + }; + + handler.postDelayed(handlerRunnable, 16); + + //Initialize runnables to be used by the input system, avoiding generating one each time is better memory. + switchStateRunnable = () -> { + currentMap.resetPressedState(); + if(lastGrabbingState){ + currentMap = gameMap; + pointerView.setVisibility(View.INVISIBLE); + mouseSensitivity = 22 / gameActivity.sensitivityFactor; //sensitivity in menus is resolution dependent. + return; + } + + currentMap = menuMap; + sendDirectionalKeycode(currentJoystickDirection, false, gameMap); // removing what we were doing + + gameActivity.mouse_x = CallbackBridge.windowWidth/2; + gameActivity.mouse_y = CallbackBridge.windowHeight/2; + CallbackBridge.sendCursorPos(gameActivity.mouse_x, gameActivity.mouse_y); + placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2); + pointerView.setVisibility(View.VISIBLE); + mouseSensitivity = 14; //sensitivity in game doesn't need to be resolution dependent + }; + + } + + + + private void tick(){ + //update mouse position + if(lastHorizontalValue != 0 || lastVerticalValue != 0){ + GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick; + + acceleration = (mouseMagnitude - currentJoystick.getDeadzone())/(1 - currentJoystick.getDeadzone()); + acceleration = Math.pow(acceleration, mouseMaxAcceleration); + if(acceleration > 1) acceleration = 1; + + CallbackBridge.mouseX += Math.cos(mouseAngle) * acceleration * mouseSensitivity; + CallbackBridge.mouseY -= Math.sin(mouseAngle) * acceleration * mouseSensitivity; + + if(!lastGrabbingState){ + CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth); + CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight); + placePointerView((int) (CallbackBridge.mouseX /gameActivity.scaleFactor), (int) (CallbackBridge.mouseY/gameActivity.scaleFactor)); + } + + gameActivity.mouse_x = CallbackBridge.mouseX; + gameActivity.mouse_y = CallbackBridge.mouseY; + + //Send the mouse to the game + CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); + } + + } + + private void updateGrabbingState() { + boolean lastGrabbingValue = lastGrabbingState; + lastGrabbingState = CallbackBridge.isGrabbing(); + if(lastGrabbingValue != lastGrabbingState){ + gameActivity.runOnUiThread(switchStateRunnable); + } + } + + public void update(KeyEvent event){ + sendButton(event); + } + + public void update(MotionEvent event){ + updateDirectionalJoystick(event); + updateMouseJoystick(event); + updateAnalogTriggers(event); + sendButton(gamepadDpad.convertEvent(event)); + } + + private void updateMouseJoystick(MotionEvent event){ + GamepadJoystick currentJoystick = lastGrabbingState ? rightJoystick : leftJoystick; + lastHorizontalValue = currentJoystick.getHorizontalAxis(event); + lastVerticalValue = currentJoystick.getVerticalAxis(event); + + mouseMagnitude = currentJoystick.getMagnitude(event); + mouseAngle = currentJoystick.getAngleRadian(event); + } + + private void updateDirectionalJoystick(MotionEvent event){ + GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick; + + int lastJoystickDirection = currentJoystickDirection; + currentJoystickDirection = currentJoystick.getHeightDirection(event); + + if(currentJoystickDirection != lastJoystickDirection){ + sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap()); + sendDirectionalKeycode(currentJoystickDirection, true, getCurrentMap()); + } + } + + private void updateAnalogTriggers(MotionEvent event){ + if(!hasDigitalTriggers){ + getCurrentMap().TRIGGER_LEFT.update((event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5) || (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)); + getCurrentMap().TRIGGER_RIGHT.update((event.getAxisValue(MotionEvent.AXIS_RTRIGGER) > 0.5) || (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)); + } + } + + public void notifyGUISizeChange(int newSize){ + //Change the pointer size to match UI + int size = (int) ((22 * newSize) / gameActivity.scaleFactor); + gameActivity.runOnUiThread(() -> pointerView.setLayoutParams(new FrameLayout.LayoutParams(size, size))); + } + + private GamepadMap getCurrentMap(){ + return currentMap; + } + + private static void sendDirectionalKeycode(int direction, boolean isDown, GamepadMap map){ + switch (direction){ + case DIRECTION_NORTH: + sendInput(map.DIRECTION_FORWARD, isDown); + break; + case DIRECTION_NORTH_EAST: + sendInput(map.DIRECTION_FORWARD, isDown); + sendInput(map.DIRECTION_RIGHT, isDown); + break; + case DIRECTION_EAST: + sendInput(map.DIRECTION_RIGHT, isDown); + break; + case DIRECTION_SOUTH_EAST: + sendInput(map.DIRECTION_RIGHT, isDown); + sendInput(map.DIRECTION_BACKWARD, isDown); + break; + case DIRECTION_SOUTH: + sendInput(map.DIRECTION_BACKWARD, isDown); + break; + case DIRECTION_SOUTH_WEST: + sendInput(map.DIRECTION_BACKWARD, isDown); + sendInput(map.DIRECTION_LEFT, isDown); + break; + case DIRECTION_WEST: + sendInput(map.DIRECTION_LEFT, isDown); + break; + case DIRECTION_NORTH_WEST: + sendInput(map.DIRECTION_FORWARD, isDown); + sendInput(map.DIRECTION_LEFT, isDown); + break; + } + } + + private void placePointerView(int x, int y){ + pointerView.setX(x - pointerView.getWidth()/2); + pointerView.setY(y - pointerView.getHeight()/2); + } + + + public void sendButton(KeyEvent event){ + int keycode = event.getKeyCode(); + switch (keycode){ + case KeyEvent.KEYCODE_BUTTON_A: + getCurrentMap().BUTTON_A.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_B: + getCurrentMap().BUTTON_B.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_X: + getCurrentMap().BUTTON_X.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_Y: + getCurrentMap().BUTTON_Y.update(event); + break; + + //Shoulders + case KeyEvent.KEYCODE_BUTTON_L1: + getCurrentMap().SHOULDER_LEFT.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_R1: + getCurrentMap().SHOULDER_RIGHT.update(event); + break; + + //Triggers + case KeyEvent.KEYCODE_BUTTON_L2: + getCurrentMap().TRIGGER_LEFT.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_R2: + getCurrentMap().TRIGGER_RIGHT.update(event); + break; + + //L3 || R3 + case KeyEvent.KEYCODE_BUTTON_THUMBL: + getCurrentMap().THUMBSTICK_LEFT.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_THUMBR: + getCurrentMap().THUMBSTICK_RIGHT.update(event); + break; + + //DPAD + case KeyEvent.KEYCODE_DPAD_UP: + getCurrentMap().DPAD_UP.update(event); + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + getCurrentMap().DPAD_DOWN.update(event); + break; + case KeyEvent.KEYCODE_DPAD_LEFT: + getCurrentMap().DPAD_LEFT.update(event); + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + getCurrentMap().DPAD_RIGHT.update(event); + break; + case KeyEvent.KEYCODE_DPAD_CENTER: + getCurrentMap().DPAD_RIGHT.update(false); + getCurrentMap().DPAD_LEFT.update(false); + getCurrentMap().DPAD_UP.update(false); + getCurrentMap().DPAD_DOWN.update(false); + break; + + //Start/select + case KeyEvent.KEYCODE_BUTTON_START: + getCurrentMap().BUTTON_START.update(event); + break; + case KeyEvent.KEYCODE_BUTTON_SELECT: + getCurrentMap().BUTTON_SELECT.update(event); + break; + + + default: + MainActivity.sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), event.getAction() == KeyEvent.ACTION_DOWN); + break; + } + } + + public static void sendInput(int[] keycodes, boolean isDown){ + for(int keycode : keycodes){ + switch (keycode){ + case GamepadMap.MOUSE_SCROLL_DOWN: + if(isDown) CallbackBridge.sendScroll(0, -1); + break; + case GamepadMap.MOUSE_SCROLL_UP: + if(isDown) CallbackBridge.sendScroll(0, 1); + break; + + case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT: + MainActivity.sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown); + break; + case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT: + MainActivity.sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown); + break; + + + default: + MainActivity.sendKeyPress(keycode, CallbackBridge.getCurrentMods(), isDown); + break; + } + CallbackBridge.setModifiers(keycode, isDown); + } + + } + + public static boolean isGamepadEvent(MotionEvent event){ + return isJoystickEvent(event); + } + + public static boolean isGamepadEvent(KeyEvent event){ + return ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD + || GamepadDpad.isDpadEvent(event) ); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadButton.java new file mode 100644 index 000000000..f502ff60f --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadButton.java @@ -0,0 +1,46 @@ +package net.kdt.pojavlaunch.customcontrols.gamepad; + +import android.view.KeyEvent; + +public class GamepadButton { + + /* + Just a simple button, that auto deal with the great habit from android to just SPAAAMS input events + */ + public int[] keycodes; + public boolean isToggleable = false; + private boolean isDown = false; + private boolean isToggled = false; + + public void update(KeyEvent event){ + boolean isKeyDown = (event.getAction() == KeyEvent.ACTION_DOWN); + update(isKeyDown); + } + + public void update(boolean isKeyDown){ + if(isKeyDown != isDown){ + isDown = isKeyDown; + if(isToggleable){ + if(isKeyDown){ + isToggled = !isToggled; + Gamepad.sendInput(keycodes, isToggled); + } + return; + } + Gamepad.sendInput(keycodes, isDown); + } + } + + public void resetButtonState(){ + if(isDown || isToggled){ + Gamepad.sendInput(keycodes, false); + } + isDown = false; + isToggled = false; + } + + public boolean isDown(){ + return isToggleable ? isToggled : isDown; + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java new file mode 100644 index 000000000..8cd12c46f --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java @@ -0,0 +1,99 @@ +package net.kdt.pojavlaunch.customcontrols.gamepad; + +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import net.kdt.pojavlaunch.LWJGLGLFWKeycode; + +import java.lang.reflect.Field; + +import static android.view.InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC; +import static android.view.InputDevice.SOURCE_DPAD; +import static android.view.KeyEvent.KEYCODE_DPAD_CENTER; +import static android.view.KeyEvent.KEYCODE_DPAD_DOWN; +import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; +import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; +import static android.view.KeyEvent.KEYCODE_DPAD_UP; + +/* + Reflection is used to avoid memory churning, and only has an negative impact at start + */ + +public class GamepadDpad { + + + private int lastKeycode = KEYCODE_DPAD_CENTER; + private KeyEvent dummyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, lastKeycode); + private Field eventCodeField; + private Field eventActionField; + + { + try { + eventCodeField = dummyEvent.getClass().getDeclaredField("mKeyCode"); + eventCodeField.setAccessible(true); + + eventActionField = dummyEvent.getClass().getDeclaredField("mAction"); + eventActionField.setAccessible(true); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public KeyEvent convertEvent(MotionEvent event){ + // Use the hat axis value to find the D-pad direction + float xaxis = event.getAxisValue(MotionEvent.AXIS_HAT_X); + float yaxis = event.getAxisValue(MotionEvent.AXIS_HAT_Y); + int action = KeyEvent.ACTION_DOWN; + + // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad + // LEFT and RIGHT direction accordingly. + if (Float.compare(xaxis, -1.0f) == 0) { + lastKeycode = KEYCODE_DPAD_LEFT; + } else if (Float.compare(xaxis, 1.0f) == 0) { + lastKeycode = KEYCODE_DPAD_RIGHT; + } + // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad + // UP and DOWN direction accordingly. + else if (Float.compare(yaxis, -1.0f) == 0) { + lastKeycode = KEYCODE_DPAD_UP; + } else if (Float.compare(yaxis, 1.0f) == 0) { + lastKeycode = KEYCODE_DPAD_DOWN; + }else { + //No keycode change + action = KeyEvent.ACTION_UP; + } + + setDummyEventKeycode(lastKeycode); + setDummyEventAction(action); + dummyEvent.setSource(SOURCE_DPAD); + return dummyEvent; + + } + + private void setDummyEventKeycode(int fakeKeycode){ + try { + eventCodeField.setInt(dummyEvent, fakeKeycode); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + private void setDummyEventAction(int action){ + try { + eventActionField.setInt(dummyEvent, action); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public static boolean isDpadEvent(MotionEvent event) { + // Check that input comes from a device with directional pads. + // And... also the joystick since it declares sometimes as a joystick. + return (event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK; + } + + public static boolean isDpadEvent(KeyEvent event){ + return ((event.getSource() & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) && (event.getDevice().getKeyboardType() == KEYBOARD_TYPE_NON_ALPHABETIC); + } +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java new file mode 100644 index 000000000..f04b26615 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java @@ -0,0 +1,95 @@ +package net.kdt.pojavlaunch.customcontrols.gamepad; + +import android.view.InputDevice; +import android.view.MotionEvent; + + +import com.google.android.material.math.MathUtils; + +public class GamepadJoystick { + + //Directions + public static final int DIRECTION_NONE = -1; //GamepadJoystick at the center + + public static final int DIRECTION_EAST = 0; + public static final int DIRECTION_NORTH_EAST = 1; + public static final int DIRECTION_NORTH = 2; + public static final int DIRECTION_NORTH_WEST = 3; + public static final int DIRECTION_WEST = 4; + public static final int DIRECTION_SOUTH_WEST = 5; + public static final int DIRECTION_SOUTH = 6; + public static final int DIRECTION_SOUTH_EAST = 7; + + private float deadzone; + + private final int verticalAxis; + private final int horizontalAxis; + + public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){ + this.verticalAxis = verticalAxis; + this.horizontalAxis = horizontalAxis; + + //Some controllers aren't recognized as such by android, so we fallback to a default value of 0.2 + //And some others don't report their MotionRange. This was the case with the xbox one series S controller. + + try { deadzone = Math.max(device.getMotionRange(verticalAxis).getFlat(), device.getMotionRange(horizontalAxis).getFlat()) * 1.9f; } + catch (NullPointerException e){ deadzone = 0.2f; } + + if(deadzone < 0.2) deadzone = 0.2f; + } + + public double getAngleRadian(MotionEvent event){ + //From -PI to PI + return -Math.atan2(getVerticalAxis(event), getHorizontalAxis(event)); + } + + + public double getAngleDegree(MotionEvent event){ + //From 0 to 360 degrees + double result = Math.toDegrees(getAngleRadian(event)); + if(result < 0) result += 360; + + return result; + } + + public double getMagnitude(MotionEvent event){ + float x = Math.abs(event.getAxisValue(horizontalAxis)); + float y = Math.abs(event.getAxisValue(verticalAxis)); + + return MathUtils.dist(0,0, x, y); + } + + public float getVerticalAxis(MotionEvent event){ + return applyDeadzone(event, verticalAxis); + } + + public float getHorizontalAxis(MotionEvent event){ + return applyDeadzone(event, horizontalAxis); + } + + private float applyDeadzone(MotionEvent event, int axis){ + //This piece of code also modifies the value + //to make it seem like there was no deadzone in the first place + + double magnitude = getMagnitude(event); + if (magnitude < deadzone) return 0; + + return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) ); + } + + public static boolean isJoystickEvent(MotionEvent event){ + return (event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK + && event.getAction() == MotionEvent.ACTION_MOVE; + } + + + public int getHeightDirection(MotionEvent event){ + if(getMagnitude(event) <= deadzone) return DIRECTION_NONE; + return ((int) ((getAngleDegree(event)+22.5)/45)) % 8; + } + + + public float getDeadzone() { + return deadzone; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMap.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMap.java new file mode 100644 index 000000000..90ec915b6 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMap.java @@ -0,0 +1,174 @@ +package net.kdt.pojavlaunch.customcontrols.gamepad; + +import net.kdt.pojavlaunch.LWJGLGLFWKeycode; + +public class GamepadMap { + + public static final int MOUSE_SCROLL_DOWN = -1; + public static final int MOUSE_SCROLL_UP = -2; + + /* + This class is just here to store the mapping + can be modified to create re-mappable controls I guess + + Be warned, you should define ALL keys if you want to avoid a non defined exception + */ + + public GamepadButton BUTTON_A = new GamepadButton(); + public GamepadButton BUTTON_B = new GamepadButton(); + public GamepadButton BUTTON_X = new GamepadButton(); + public GamepadButton BUTTON_Y = new GamepadButton(); + + public GamepadButton BUTTON_START = new GamepadButton(); + public GamepadButton BUTTON_SELECT = new GamepadButton(); + + public GamepadButton TRIGGER_RIGHT = new GamepadButton(); //R2 + public GamepadButton TRIGGER_LEFT = new GamepadButton(); //L2 + + public GamepadButton SHOULDER_RIGHT = new GamepadButton(); //R1 + public GamepadButton SHOULDER_LEFT = new GamepadButton(); //L1 + + public int[] DIRECTION_FORWARD; + public int[] DIRECTION_BACKWARD; + public int[] DIRECTION_RIGHT; + public int[] DIRECTION_LEFT; + + public GamepadButton THUMBSTICK_RIGHT = new GamepadButton(); //R3 + public GamepadButton THUMBSTICK_LEFT = new GamepadButton(); //L3 + + public GamepadButton DPAD_UP = new GamepadButton(); + public GamepadButton DPAD_RIGHT = new GamepadButton(); + public GamepadButton DPAD_DOWN = new GamepadButton(); + public GamepadButton DPAD_LEFT = new GamepadButton(); + + + /* + * Sets all buttons to a not pressed state, sending an input if needed + */ + public void resetPressedState(){ + BUTTON_A.resetButtonState(); + BUTTON_B.resetButtonState(); + BUTTON_X.resetButtonState(); + BUTTON_Y.resetButtonState(); + + BUTTON_START.resetButtonState(); + BUTTON_SELECT.resetButtonState(); + + TRIGGER_LEFT.resetButtonState(); + TRIGGER_RIGHT.resetButtonState(); + + SHOULDER_LEFT.resetButtonState(); + SHOULDER_RIGHT.resetButtonState(); + + THUMBSTICK_LEFT.resetButtonState(); + THUMBSTICK_RIGHT.resetButtonState(); + + DPAD_UP.resetButtonState(); + DPAD_RIGHT.resetButtonState(); + DPAD_DOWN.resetButtonState(); + DPAD_LEFT.resetButtonState(); + + } + + /* + * Returns a pre-done mapping used when the mouse is grabbed by the game. + */ + public static GamepadMap getDefaultGameMap(){ + GamepadMap gameMap = new GamepadMap(); + + gameMap.BUTTON_A.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_SPACE}; + gameMap.BUTTON_B.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_Q}; + gameMap.BUTTON_X.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_E}; + gameMap.BUTTON_Y.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_F}; + + gameMap.DIRECTION_FORWARD = new int[]{LWJGLGLFWKeycode.GLFW_KEY_W}; + gameMap.DIRECTION_BACKWARD = new int[]{LWJGLGLFWKeycode.GLFW_KEY_S}; + gameMap.DIRECTION_RIGHT = new int[]{LWJGLGLFWKeycode.GLFW_KEY_D}; + gameMap.DIRECTION_LEFT = new int[]{LWJGLGLFWKeycode.GLFW_KEY_A}; + + gameMap.DPAD_UP.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT}; + gameMap.DPAD_DOWN.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_O}; //For mods ? + gameMap.DPAD_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_K}; //For mods ? + gameMap.DPAD_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_J}; //For mods ? + + gameMap.SHOULDER_LEFT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_UP}; + gameMap.SHOULDER_RIGHT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_DOWN}; + + gameMap.TRIGGER_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT}; + gameMap.TRIGGER_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT}; + + gameMap.THUMBSTICK_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL}; + gameMap.THUMBSTICK_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT}; + gameMap.THUMBSTICK_RIGHT.isToggleable = true; + + gameMap.BUTTON_START.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE}; + gameMap.BUTTON_SELECT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_TAB}; + + return gameMap; + } + + /* + * Returns a pre-done mapping used when the mouse is NOT grabbed by the game. + */ + public static GamepadMap getDefaultMenuMap(){ + GamepadMap menuMap = new GamepadMap(); + + menuMap.BUTTON_A.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT}; + menuMap.BUTTON_B.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE}; + menuMap.BUTTON_X.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT}; + menuMap.BUTTON_Y.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT, LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT}; //Oops, doesn't work since left shift isn't properly applied. + + menuMap.DIRECTION_FORWARD = new int[]{GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP}; + menuMap.DIRECTION_BACKWARD = new int[]{GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN}; + menuMap.DIRECTION_RIGHT = new int[]{}; + menuMap.DIRECTION_LEFT = new int[]{}; + + menuMap.DPAD_UP.keycodes = new int[]{}; + menuMap.DPAD_DOWN.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_O}; //For mods ? + menuMap.DPAD_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_K}; //For mods ? + menuMap.DPAD_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_J}; //For mods ? + + menuMap.SHOULDER_LEFT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_UP}; + menuMap.SHOULDER_RIGHT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_DOWN}; + + menuMap.TRIGGER_LEFT.keycodes = new int[]{}; + menuMap.TRIGGER_RIGHT.keycodes = new int[]{}; + + menuMap.THUMBSTICK_LEFT.keycodes = new int[]{}; + menuMap.THUMBSTICK_RIGHT.keycodes = new int[]{}; + + menuMap.BUTTON_START.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE}; + menuMap.BUTTON_SELECT.keycodes = new int[]{}; + + return menuMap; + } + + /* + * Returns all GamepadButtons, does not include directional keys + */ + public GamepadButton[] getButtons(){ + return new GamepadButton[]{ BUTTON_A, BUTTON_B, BUTTON_X, BUTTON_Y, + BUTTON_SELECT, BUTTON_START, + TRIGGER_LEFT, TRIGGER_RIGHT, + SHOULDER_LEFT, SHOULDER_RIGHT, + THUMBSTICK_LEFT, THUMBSTICK_RIGHT, + DPAD_UP, DPAD_RIGHT, DPAD_DOWN, DPAD_LEFT}; + } + + /* + * Returns an pre-initialized GamepadMap with only empty keycodes + */ + public static GamepadMap getEmptyMap(){ + GamepadMap emptyMap = new GamepadMap(); + for(GamepadButton button : emptyMap.getButtons()) + button.keycodes = new int[]{}; + + emptyMap.DIRECTION_LEFT = new int[]{}; + emptyMap.DIRECTION_FORWARD = new int[]{}; + emptyMap.DIRECTION_RIGHT = new int[]{}; + emptyMap.DIRECTION_BACKWARD = new int[]{}; + + return emptyMap; + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/ActionPopupWindow.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/ActionPopupWindow.java index 6ae0bb636..cbcc33aad 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/ActionPopupWindow.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/ActionPopupWindow.java @@ -20,6 +20,7 @@ package net.kdt.pojavlaunch.customcontrols.handleview; import android.content.*; +import android.graphics.drawable.ColorDrawable; import android.view.*; import android.view.ViewGroup.*; import android.widget.*; @@ -28,14 +29,24 @@ import net.kdt.pojavlaunch.*; import android.view.View.OnClickListener; import net.kdt.pojavlaunch.customcontrols.*; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton; + import androidx.appcompat.app.*; +import com.rarepebble.colorpicker.ColorPickerView; + public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListener { + private TextView mEditTextView; private TextView mDeleteTextView; - - public ActionPopupWindow(HandleView handleView) { + + private Object editedButton; + + public ActionPopupWindow(HandleView handleView, Object object){ super(handleView); + this.editedButton = object; } @Override @@ -77,178 +88,50 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe @Override public void onClick(final View view) { - AlertDialog.Builder alert = new AlertDialog.Builder(view.getContext()); - alert.setCancelable(false); if (view == mEditTextView) { - alert.setTitle(view.getResources().getString(R.string.customctrl_edit, mHandleView.mView.getText())); - alert.setView(R.layout.control_setting); - alert.setPositiveButton(android.R.string.ok, null); - alert.setNegativeButton(android.R.string.cancel, null); - final AlertDialog dialog = alert.create(); - final ControlData properties = mHandleView.mView.getProperties(); - dialog.setOnShowListener(new DialogInterface.OnShowListener() { + if(editedButton instanceof ControlSubButton){ + new EditControlSubButtonPopup((ControlSubButton) editedButton); + return; + } - @Override - public void onShow(DialogInterface dialogInterface) { - final EditText editName = dialog.findViewById(R.id.controlsetting_edit_name); - editName.setText(properties.name); + if(editedButton instanceof ControlDrawer){ + new EditControlDrawerPopup((ControlDrawer) editedButton); + return; + } - final Spinner spinnerKeycode = dialog.findViewById(R.id.controlsetting_spinner_lwjglkeycode); - ArrayAdapter adapter = new ArrayAdapter(view.getContext(), android.R.layout.simple_spinner_item); + if(editedButton instanceof ControlButton){ + new EditControlButtonPopup((ControlButton) editedButton); + return; + } - String[] oldSpecialArr = ControlData.buildSpecialButtonArray(); - final String[] specialArr = new String[oldSpecialArr.length]; - for (int i = 0; i < specialArr.length; i++) { - specialArr[i] = "SPECIAL_" + oldSpecialArr[specialArr.length - i - 1]; - } - adapter.addAll(specialArr); - adapter.addAll(AndroidLWJGLKeycode.generateKeyName()); - adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); - spinnerKeycode.setAdapter(adapter); - if (properties.keycode < 0) { - spinnerKeycode.setSelection(properties.keycode + specialArr.length); - } else { - spinnerKeycode.setSelection(AndroidLWJGLKeycode.getIndexByLWJGLKey(properties.keycode) + specialArr.length); - } - - final CheckBox checkToggle = dialog.findViewById(R.id.controlsetting_checkbox_toggle); - checkToggle.setChecked(properties.isToggle); - final CheckBox checkPassthru = dialog.findViewById(R.id.controlsetting_checkbox_passthru); - checkPassthru.setChecked(properties.passThruEnabled); - final CheckBox checkRound = dialog.findViewById(R.id.controlsetting_checkbox_round); - checkRound.setChecked(properties.isRound); - final EditText editWidth = dialog.findViewById(R.id.controlsetting_edit_width); - final EditText editHeight = dialog.findViewById(R.id.controlsetting_edit_height); - editWidth.setText(Float.toString(properties.width)); - editHeight.setText(Float.toString(properties.height)); - - final EditText editDynamicX = dialog.findViewById(R.id.controlsetting_edit_dynamicpos_x); - final EditText editDynamicY = dialog.findViewById(R.id.controlsetting_edit_dynamicpos_y); - editDynamicX.setEnabled(properties.isDynamicBtn); - editDynamicY.setEnabled(properties.isDynamicBtn); - - final SeekBar seekTransparency = dialog.findViewById(R.id.controlsetting_seek_transparency); - seekTransparency.setMax(100); - seekTransparency.setProgress(properties.hidden ? 100 : properties.transparency); - - final CheckBox checkDynamicPos = dialog.findViewById(R.id.controlsetting_checkbox_dynamicpos); - checkDynamicPos.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){ - - @Override - public void onCheckedChanged(CompoundButton btn, boolean checked) { - editDynamicX.setEnabled(checked); - editDynamicY.setEnabled(checked); - } - }); - checkDynamicPos.setChecked(properties.isDynamicBtn); - - editDynamicX.setHint(Float.toString(properties.x)); - editDynamicX.setText(properties.dynamicX); - - editDynamicY.setHint(Float.toString(properties.y)); - editDynamicY.setText(properties.dynamicY); - - final CheckBox checkHoldAlt = dialog.findViewById(R.id.controlsetting_checkbox_keycombine_alt); - checkHoldAlt.setChecked(properties.holdAlt); - - final CheckBox checkHoldControl = dialog.findViewById(R.id.controlsetting_checkbox_keycombine_control); - checkHoldControl.setChecked(properties.holdCtrl); - - final CheckBox checkHoldShift = dialog.findViewById(R.id.controlsetting_checkbox_keycombine_shift); - checkHoldShift.setChecked(properties.holdShift); - - Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); - button.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View view2) { - if (editName.getText().toString().isEmpty()) { - editName.setError(view.getResources().getString(R.string.global_error_field_empty)); - } else { - /* - String errorAt = null; - try { - errorAt = "DynamicX"; - properties.insertDynamicPos(editDynamicX.getText().toString()); - errorAt = "DynamicY"; - properties.insertDynamicPos(editDynamicY.getText().toString()); - } catch (Throwable th) { - Error e = new Error(errorAt, th); - e.setStackTrace(null); - Tools.showError(view.getContext(), e); - return; - } - errorAt = null; - */ - - if (properties.isDynamicBtn) { - int errorAt = 0; - try { - properties.insertDynamicPos(editDynamicX.getText().toString()); - errorAt = 1; - properties.insertDynamicPos(editDynamicY.getText().toString()); - } catch (Throwable th) { - (errorAt == 0 ? editDynamicX : editDynamicY) - .setError(th.getMessage()); - - return; - } - } - - if (spinnerKeycode.getSelectedItemPosition() < specialArr.length) { - properties.keycode = spinnerKeycode.getSelectedItemPosition() - specialArr.length; - } else { - properties.keycode = AndroidLWJGLKeycode.getKeyByIndex(spinnerKeycode.getSelectedItemPosition() - specialArr.length); - } - properties.name = editName.getText().toString(); - - properties.transparency = seekTransparency.getProgress(); - - properties.hidden = false; - properties.isToggle = checkToggle.isChecked(); - properties.passThruEnabled = checkPassthru.isChecked(); - properties.isRound = checkRound.isChecked(); - properties.isDynamicBtn = checkDynamicPos.isChecked(); - properties.width = Float.parseFloat(editWidth.getText().toString()); - properties.height = Float.parseFloat(editHeight.getText().toString()); - properties.dynamicX = editDynamicX.getText().toString(); - properties.dynamicY = editDynamicY.getText().toString(); - - properties.holdAlt = checkHoldAlt.isChecked(); - properties.holdCtrl = checkHoldControl.isChecked(); - properties.holdShift = checkHoldShift.isChecked(); - - if (properties.dynamicX.isEmpty()) { - properties.dynamicX = Float.toString(properties.x); - } if (properties.dynamicY.isEmpty()) { - properties.dynamicY = Float.toString(properties.y); - } - - mHandleView.mView.updateProperties(); - - dialog.dismiss(); - } - } - }); - } - }); - - dialog.show(); } else if (view == mDeleteTextView) { - alert.setMessage(view.getContext().getString(R.string.customctrl_remove, mHandleView.mView.getText()) + "?"); - alert.setPositiveButton(R.string.global_remove, new DialogInterface.OnClickListener(){ + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(view.getContext()); + alertBuilder.setCancelable(false); + alertBuilder.setMessage(view.getContext().getString(R.string.customctrl_remove, mHandleView.mView.getText()) + "?"); - @Override - public void onClick(DialogInterface p1, int p2) - { - ControlLayout layout = ((ControlLayout) mHandleView.mView.getParent()); - layout.removeControlButton(mHandleView.mView); - } - }); - alert.setNegativeButton(android.R.string.cancel, null); - alert.show(); + alertBuilder.setPositiveButton(R.string.global_remove, (p1, p2) -> { + ControlLayout layout = ((ControlLayout) mHandleView.mView.getParent()); + + if(editedButton instanceof ControlSubButton){ + layout.removeControlSubButton((ControlSubButton) editedButton); + return; + } + + if(editedButton instanceof ControlDrawer){ + layout.removeControlDrawer((ControlDrawer) editedButton); + return; + } + + if(editedButton instanceof ControlButton){ + layout.removeControlButton((ControlButton) editedButton); + } + + layout.removeControlButton(mHandleView.mView); + }); + alertBuilder.setNegativeButton(android.R.string.cancel, null); + alertBuilder.show(); } hide(); @@ -257,32 +140,37 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe @Override protected int getTextOffset() { return 0; - // return (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2; } @Override protected int getVerticalLocalPosition(int line) { - // return mTextView.getLayout().getLineTop(line) - mContentView.getMeasuredHeight(); return 0; } @Override protected int clipVertically(int positionY) { - /* - if (positionY < 0) { - final int offset = getTextOffset(); - final Layout layout = mTextView.getLayout(); - final int line = layout.getLineForOffset(offset); - positionY += layout.getLineBottom(line) - layout.getLineTop(line); - positionY += mContentView.getMeasuredHeight(); - - // Assumes insertion and selection handles share the same height - final Drawable handle = mHandleView.getContext().getDrawable( - mTextView.mTextSelectHandleRes); - positionY += handle.getIntrinsicHeight(); - } - */ - return positionY; } + + + public static void showColorPicker(Context ctx,String title, boolean showAlpha, ImageView v){ + int startColor = ((ColorDrawable)v.getDrawable()).getColor(); + + ColorPickerView picker = new ColorPickerView(ctx); + picker.setColor(startColor); + picker.showAlpha(showAlpha); + + AlertDialog.Builder dialog = new AlertDialog.Builder(ctx); + dialog.setTitle(title); + dialog.setView(picker); + dialog.setNegativeButton(android.R.string.cancel, null); + dialog.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> v.setImageDrawable(new ColorDrawable(picker.getColor()))); + + dialog.show(); + } + + public static void setPercentageText(TextView textView, int progress){ + textView.setText(progress + " %"); + } + } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlButtonPopup.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlButtonPopup.java new file mode 100644 index 000000000..6c138ebf8 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlButtonPopup.java @@ -0,0 +1,306 @@ +package net.kdt.pojavlaunch.customcontrols.handleview; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.Spinner; +import android.widget.TextView; + +import androidx.appcompat.app.AlertDialog; + +import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode; +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; +import net.kdt.pojavlaunch.customcontrols.ControlData; + +import top.defaults.checkerboarddrawable.CheckerboardDrawable; + +import static net.kdt.pojavlaunch.customcontrols.handleview.ActionPopupWindow.setPercentageText; + +public class EditControlButtonPopup { + + protected Dialog dialog; + protected View v; + protected AlertDialog.Builder builder; + + protected EditText editName; + protected Spinner[] spinnersKeycode; + + protected CheckBox checkToggle; + protected CheckBox checkPassThrough; + protected CheckBox checkBoxSwipeable; + protected CheckBox checkDynamicPosition; + + protected EditText editWidth; + protected EditText editHeight; + protected EditText editDynamicX; + protected EditText editDynamicY; + + protected SeekBar seekBarOpacity; + protected SeekBar seekBarCornerRadius; + protected SeekBar seekBarStrokeWidth; + + protected ImageButton buttonBackgroundColor; + protected ImageButton buttonStrokeColor; + + protected TextView textOpacity; + protected TextView textCornerRadius; + protected TextView textStrokeWidth; + + protected final ControlButton button; + protected final ControlData properties; + + protected ArrayAdapter adapter; + protected String[] specialArr; + + + public EditControlButtonPopup(ControlButton button){ + this.button = button; + this.properties = button.getProperties(); + + initializeEditDialog(button.getContext()); + + //Create the finalized dialog + dialog = builder.create(); + dialog.setOnShowListener(dialogInterface -> setEditDialogValues()); + + + dialog.show(); + } + + protected void initializeEditDialog(Context ctx){ + //Create the editing dialog + LayoutInflater layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = layoutInflater.inflate(R.layout.control_button_setting,null); + + builder = new AlertDialog.Builder(ctx); + builder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, properties.name)); + builder.setView(v); + + //Linking a lot of stuff + editName = v.findViewById(R.id.editName_editText); + + spinnersKeycode = new Spinner[]{ + v.findViewById(R.id.editMapping_spinner_1), + v.findViewById(R.id.editMapping_spinner_2), + v.findViewById(R.id.editMapping_spinner_3), + v.findViewById(R.id.editMapping_spinner_4) + }; + + checkToggle = v.findViewById(R.id.checkboxToggle); + checkPassThrough = v.findViewById(R.id.checkboxPassThrough); + checkBoxSwipeable = v.findViewById(R.id.checkboxSwipeable); + + editWidth = v.findViewById(R.id.editSize_editTextX); + editHeight = v.findViewById(R.id.editSize_editTextY); + + editDynamicX = v.findViewById(R.id.editDynamicPositionX_editText); + editDynamicY = v.findViewById(R.id.editDynamicPositionY_editText); + + seekBarOpacity = v.findViewById(R.id.editButtonOpacity_seekbar); + seekBarCornerRadius = v.findViewById(R.id.editCornerRadius_seekbar); + seekBarStrokeWidth = v.findViewById(R.id.editStrokeWidth_seekbar); + + SeekBar.OnSeekBarChangeListener changeListener = new SeekBar.OnSeekBarChangeListener() { + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + if(seekBar.equals(seekBarCornerRadius)) { + setPercentageText(textCornerRadius, i); + return; + } + if(seekBar.equals(seekBarOpacity)) { + setPercentageText(textOpacity, i); + return; + } + if(seekBar.equals(seekBarStrokeWidth)) { + setPercentageText(textStrokeWidth, i); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) {/*STUB*/} + @Override + public void onStopTrackingTouch(SeekBar seekBar) {/*STUB*/} + }; + + //Add listeners, too bad I don't need all the methods + seekBarOpacity.setOnSeekBarChangeListener(changeListener); + seekBarCornerRadius.setOnSeekBarChangeListener(changeListener); + seekBarStrokeWidth.setOnSeekBarChangeListener(changeListener); + + buttonBackgroundColor = v.findViewById(R.id.editBackgroundColor_imageButton); + buttonStrokeColor = v.findViewById(R.id.editStrokeColor_imageButton); + + textOpacity = v.findViewById(R.id.editButtonOpacity_textView_percent); + textCornerRadius = v.findViewById(R.id.editCornerRadius_textView_percent); + textStrokeWidth = v.findViewById(R.id.editStrokeWidth_textView_percent); + + checkDynamicPosition = v.findViewById(R.id.checkboxDynamicPosition); + checkDynamicPosition.setOnCheckedChangeListener((btn, checked) -> { + editDynamicX.setEnabled(checked); + editDynamicY.setEnabled(checked); + }); + + + //Initialize adapter for keycodes + adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item); + String[] oldSpecialArr = ControlData.buildSpecialButtonArray(); + specialArr = new String[oldSpecialArr.length]; + for (int i = 0; i < specialArr.length; i++) { + specialArr[i] = "SPECIAL_" + oldSpecialArr[specialArr.length - i - 1]; + } + adapter.addAll(specialArr); + adapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName()); + adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); + + for (Spinner spinner : spinnersKeycode) { + spinner.setAdapter(adapter); + } + + //Set color imageButton behavior + buttonBackgroundColor.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit background color", true, buttonBackgroundColor)); + buttonStrokeColor.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit stroke color", false, buttonStrokeColor)); + + + //Set dialog buttons behavior + setupDialogButtons(); + + hideUselessViews(); + + setupCheckerboards(); + } + + protected void setupDialogButtons(){ + //Set dialog buttons behavior + builder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> { + if(!hasPropertiesErrors(dialog.getContext())){ + saveProperties(); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + } + + protected void hideUselessViews(){ + (v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE); + } + + private void setupCheckerboards(){ + CheckerboardDrawable drawable = new CheckerboardDrawable.Builder() + .colorEven(Color.LTGRAY) + .colorOdd(Color.WHITE) + .size((int) Tools.dpToPx(20)) + .build(); + + buttonBackgroundColor.setBackground(drawable); + buttonStrokeColor.setBackground(drawable); + } + + protected void setEditDialogValues(){ + + editName.setText(properties.name); + + checkToggle.setChecked(properties.isToggle); + checkPassThrough.setChecked(properties.passThruEnabled); + checkBoxSwipeable.setChecked(properties.isSwipeable); + + editWidth.setText(Float.toString(properties.getWidth())); + editHeight.setText(Float.toString(properties.getHeight())); + + editDynamicX.setEnabled(properties.isDynamicBtn); + editDynamicY.setEnabled(properties.isDynamicBtn); + editDynamicX.setHint(Float.toString(properties.x)); + editDynamicX.setText(properties.dynamicX); + editDynamicY.setHint(Float.toString(properties.y)); + editDynamicY.setText(properties.dynamicY); + + seekBarOpacity.setProgress((int) (properties.opacity*100)); + seekBarStrokeWidth.setProgress(properties.strokeWidth); + seekBarCornerRadius.setProgress((int)properties.cornerRadius); + + buttonBackgroundColor.setImageDrawable(new ColorDrawable(properties.bgColor)); + buttonStrokeColor.setImageDrawable(new ColorDrawable(properties.strokeColor)); + + setPercentageText(textCornerRadius,seekBarCornerRadius.getProgress()); + setPercentageText(textOpacity,seekBarOpacity.getProgress()); + setPercentageText(textStrokeWidth,seekBarStrokeWidth.getProgress()); + + checkDynamicPosition.setChecked(properties.isDynamicBtn); + + for(int i=0; i< properties.keycodes.length; i++){ + if (properties.keycodes[i] < 0) { + spinnersKeycode[i].setSelection(properties.keycodes[i] + specialArr.length); + } else { + spinnersKeycode[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(properties.keycodes[i]) + specialArr.length); + } + } + } + + + protected boolean hasPropertiesErrors(Context ctx){ + if (editName.getText().toString().isEmpty()) { + editName.setError(ctx.getResources().getString(R.string.global_error_field_empty)); + return true; + } + + if (properties.isDynamicBtn) { + + int errorAt = 0; + try { + properties.insertDynamicPos(editDynamicX.getText().toString()); + errorAt = 1; + properties.insertDynamicPos(editDynamicY.getText().toString()); + } catch (Throwable th) { + (errorAt == 0 ? editDynamicX : editDynamicY).setError(th.getMessage()); + + return true; + } + } + + return false; + } + + protected void saveProperties(){ + //This method assumes there are no error. + properties.name = editName.getText().toString(); + + //Keycodes + for(int i=0; i adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item); + adapter.addAll(ControlDrawerData.getOrientations()); + adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); + + spinnerOrientation.setAdapter(adapter); + } + + @Override + protected void setEditDialogValues() { + super.setEditDialogValues(); + + spinnerOrientation.setSelection(ControlDrawerData.orientationToInt(drawerData.orientation)); + } + + @Override + protected void setupDialogButtons() { + super.setupDialogButtons(); + + builder.setNeutralButton(v.getResources().getString(R.string.customctrl_addsubbutton), (dialogInterface, i) -> { + ControlLayout layout = (ControlLayout) drawer.getParent(); + ControlData controlData = drawerData.properties.clone(); + controlData.name = "new"; + layout.addSubButton(drawer, controlData); + }); + + } + + @Override + protected void saveProperties() { + drawerData.orientation = ControlDrawerData.intToOrientation(spinnerOrientation.getSelectedItemPosition()); + super.saveProperties(); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlSubButtonPopup.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlSubButtonPopup.java new file mode 100644 index 000000000..064a5829e --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlSubButtonPopup.java @@ -0,0 +1,28 @@ +package net.kdt.pojavlaunch.customcontrols.handleview; + +import android.view.View; + +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; + +public class EditControlSubButtonPopup extends EditControlButtonPopup{ + + + public EditControlSubButtonPopup(ControlButton button){ + super(button); + } + + @Override + protected void hideUselessViews() { + (v.findViewById(R.id.editSize_textView)).setVisibility(View.GONE); + (v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE); + + checkDynamicPosition.setVisibility(View.GONE); + + (v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE); + editDynamicX.setVisibility(View.GONE); + + (v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE); + editDynamicY.setVisibility(View.GONE); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/HandleView.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/HandleView.java index 744a8e3ae..46e122905 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/HandleView.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/HandleView.java @@ -22,13 +22,12 @@ package net.kdt.pojavlaunch.customcontrols.handleview; import android.graphics.*; import android.graphics.drawable.*; import android.os.*; -import android.text.*; import android.view.*; import android.widget.*; -import android.content.*; -import java.lang.reflect.*; + import net.kdt.pojavlaunch.*; -import net.kdt.pojavlaunch.customcontrols.*; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; + public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener { @@ -100,6 +99,7 @@ public abstract class HandleView extends View implements ViewPositionListener, V mIdealVerticalOffset = 0.7f * handleHeight; } + protected void updateDrawable() { // final int offset = getCurrentCursorOffset(); final boolean isRtlCharAtOffset = true; // mView.getLayout().isRtlCharAt(offset); @@ -189,9 +189,9 @@ public abstract class HandleView extends View implements ViewPositionListener, V getPositionListener().removeSubscriber(this); } - void showActionPopupWindow(int delay) { + void showActionPopupWindow(int delay, Object object) { if (mActionPopupWindow == null) { - mActionPopupWindow = new ActionPopupWindow(this); + mActionPopupWindow = new ActionPopupWindow(this, object); } if (mActionPopupShower == null) { mActionPopupShower = new Runnable() { @@ -314,13 +314,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V protected int getCursorOffset() { return 0; } - - // Addition - @Override - public boolean onLongClick(View view) { - showActionPopupWindow(0); - return true; - } // Addition private float mDownX, mDownY; diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/SelectionEndHandleView.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/SelectionEndHandleView.java index 065a94320..eb606da4e 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/SelectionEndHandleView.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/SelectionEndHandleView.java @@ -20,10 +20,10 @@ package net.kdt.pojavlaunch.customcontrols.handleview; import android.graphics.drawable.*; -import android.text.*; import android.view.*; -import android.os.*; -import net.kdt.pojavlaunch.customcontrols.*; + +import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; + public class SelectionEndHandleView extends HandleView { @@ -50,11 +50,9 @@ public class SelectionEndHandleView extends HandleView return 0; // mView.getSelectionEnd(); } - @Override - public void show() { + public void show(Object object){ super.show(); - - showActionPopupWindow(0); + showActionPopupWindow(0, object); } @Override @@ -68,10 +66,11 @@ public class SelectionEndHandleView extends HandleView // updatePosition((int) x, (int) y, false, false); positionAtCursorOffset(0, false); } - /* - public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) { - mActionPopupWindow = actionPopupWindow; - } - */ + + @Override + public boolean onLongClick(View view) { + //TODO stub + return false; + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java index b6b82e15d..a4c84e579 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java @@ -8,21 +8,21 @@ public class LauncherPreferences { public static SharedPreferences DEFAULT_PREF; public static String PREF_RENDERER = "opengles2"; - public static boolean PREF_VERTYPE_RELEASE = true; - public static boolean PREF_VERTYPE_SNAPSHOT = false; - public static boolean PREF_VERTYPE_OLDALPHA = false; - public static boolean PREF_VERTYPE_OLDBETA = false; - public static boolean PREF_FREEFORM = false; - public static boolean PREF_HIDE_SIDEBAR = false; - public static boolean PREF_IGNORE_NOTCH = false; - public static boolean PREF_BACK_TO_RIGHT_MOUSE = false; - public static boolean PREF_BUTTON_FLAT = false; - public static int PREF_NOTCH_SIZE = 0; - public static float PREF_BUTTONSIZE = 100f; - public static float PREF_MOUSESCALE = 100f; - public static int PREF_LONGPRESS_TRIGGER = 500; - public static String PREF_DEFAULTCTRL_PATH = Tools.CTRLDEF_FILE; - public static String PREF_CUSTOM_JAVA_ARGS; + + public static boolean PREF_VERTYPE_RELEASE = true; + public static boolean PREF_VERTYPE_SNAPSHOT = false; + public static boolean PREF_VERTYPE_OLDALPHA = false; + public static boolean PREF_VERTYPE_OLDBETA = false; + public static boolean PREF_FREEFORM = false; + public static boolean PREF_HIDE_SIDEBAR = false; + public static boolean PREF_IGNORE_NOTCH = false; + public static boolean PREF_BACK_TO_RIGHT_MOUSE = false; + public static int PREF_NOTCH_SIZE = 0; + public static float PREF_BUTTONSIZE = 100f; + public static float PREF_MOUSESCALE = 100f; + public static int PREF_LONGPRESS_TRIGGER = 500; + public static String PREF_DEFAULTCTRL_PATH = Tools.CTRLDEF_FILE; + public static String PREF_CUSTOM_JAVA_ARGS; public static String PREF_CUSTOM_OPENGL_LIBNAME = "libgl4es_114.so"; public static String PREF_LANGUAGE = "default"; public static String PREF_VERSION_REPOS = "https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"; @@ -33,20 +33,20 @@ public class LauncherPreferences public static String PREF_DEFAULT_RUNTIME; public static void loadPreferences() { PREF_RENDERER = DEFAULT_PREF.getString("renderer", "opengles2"); - PREF_BUTTONSIZE = DEFAULT_PREF.getInt("buttonscale", 100); - PREF_MOUSESCALE = DEFAULT_PREF.getInt("mousescale", 100); - PREF_MOUSESPEED = ((float)DEFAULT_PREF.getInt("mousespeed",100))/100f; - PREF_FREEFORM = DEFAULT_PREF.getBoolean("freeform", false); - PREF_HIDE_SIDEBAR = DEFAULT_PREF.getBoolean("hideSidebar", false); - PREF_IGNORE_NOTCH = DEFAULT_PREF.getBoolean("ignoreNotch", false); - PREF_BACK_TO_RIGHT_MOUSE = DEFAULT_PREF.getBoolean("backToRightMouse", false); - PREF_BUTTON_FLAT = DEFAULT_PREF.getBoolean("flatButtonStyle", false); - PREF_VERTYPE_RELEASE = DEFAULT_PREF.getBoolean("vertype_release", true); - PREF_VERTYPE_SNAPSHOT = DEFAULT_PREF.getBoolean("vertype_snapshot", false); - PREF_VERTYPE_OLDALPHA = DEFAULT_PREF.getBoolean("vertype_oldalpha", false); - PREF_VERTYPE_OLDBETA = DEFAULT_PREF.getBoolean("vertype_oldbeta", false); - PREF_LONGPRESS_TRIGGER = DEFAULT_PREF.getInt("timeLongPressTrigger", 500); - PREF_DEFAULTCTRL_PATH = DEFAULT_PREF.getString("defaultCtrl", Tools.CTRLDEF_FILE); + + PREF_BUTTONSIZE = DEFAULT_PREF.getInt("buttonscale", 100); + PREF_MOUSESCALE = DEFAULT_PREF.getInt("mousescale", 100); + PREF_MOUSESPEED = ((float)DEFAULT_PREF.getInt("mousespeed",100))/100f; + PREF_FREEFORM = DEFAULT_PREF.getBoolean("freeform", false); + PREF_HIDE_SIDEBAR = DEFAULT_PREF.getBoolean("hideSidebar", false); + PREF_IGNORE_NOTCH = DEFAULT_PREF.getBoolean("ignoreNotch", false); + PREF_BACK_TO_RIGHT_MOUSE = DEFAULT_PREF.getBoolean("backToRightMouse", false); + PREF_VERTYPE_RELEASE = DEFAULT_PREF.getBoolean("vertype_release", true); + PREF_VERTYPE_SNAPSHOT = DEFAULT_PREF.getBoolean("vertype_snapshot", false); + PREF_VERTYPE_OLDALPHA = DEFAULT_PREF.getBoolean("vertype_oldalpha", false); + PREF_VERTYPE_OLDBETA = DEFAULT_PREF.getBoolean("vertype_oldbeta", false); + PREF_LONGPRESS_TRIGGER = DEFAULT_PREF.getInt("timeLongPressTrigger", 500); + PREF_DEFAULTCTRL_PATH = DEFAULT_PREF.getString("defaultCtrl", Tools.CTRLDEF_FILE); PREF_LANGUAGE = DEFAULT_PREF.getString("language", "default"); PREF_CHECK_LIBRARY_SHA = DEFAULT_PREF.getBoolean("checkLibraries",true); PREF_DISABLE_GESTURES = DEFAULT_PREF.getBoolean("disableGestures",false); diff --git a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java index 3d42cbcca..94111f036 100644 --- a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -44,15 +44,15 @@ public class CallbackBridge { } private static boolean threadAttached; - public static void sendCursorPos(int x, int y) { + public static void sendCursorPos(float x, float y) { if (!threadAttached) { threadAttached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall); } - DEBUG_STRING.append("CursorPos=" + x + ", " + y + "\n"); - mouseX = x; - mouseY = y; - nativeSendCursorPos(x, y); + DEBUG_STRING.append("CursorPos=").append(x).append(", ").append(y).append("\n"); + mouseX = (int) x; + mouseY = (int) y; + nativeSendCursorPos(mouseX, mouseY); } public static void sendPrepareGrabInitialPos() { @@ -61,7 +61,7 @@ public class CallbackBridge { } public static void sendKeycode(int keycode, char keychar, int scancode, int modifiers, boolean isDown) { - DEBUG_STRING.append("KeyCode=" + keycode + ", Char=" + keychar); + DEBUG_STRING.append("KeyCode=").append(keycode).append(", Char=").append(keychar); // TODO CHECK: This may cause input issue, not receive input! /* if (!nativeSendCharMods((int) keychar, modifiers) || !nativeSendChar(keychar)) { @@ -71,7 +71,7 @@ public class CallbackBridge { //nativeSendKeycode(keycode, keychar, scancode, isDown ? 1 : 0, modifiers); if(keycode != 0) nativeSendKey(keycode,scancode,isDown ? 1 : 0, modifiers); - else nativeSendKey(32,scancode,isDown ? 1 : 0, modifiers); + //else nativeSendKey(32,scancode,isDown ? 1 : 0, modifiers); if(isDown && keychar != '\u0000') { nativeSendCharMods(keychar,modifiers); nativeSendChar(keychar); @@ -81,7 +81,7 @@ public class CallbackBridge { } public static void sendMouseKeycode(int button, int modifiers, boolean isDown) { - DEBUG_STRING.append("MouseKey=" + button + ", down=" + isDown + "\n"); + DEBUG_STRING.append("MouseKey=").append(button).append(", down=").append(isDown).append("\n"); // if (isGrabbing()) DEBUG_STRING.append("MouseGrabStrace: " + android.util.Log.getStackTraceString(new Throwable()) + "\n"); nativeSendMouseButton(button, isDown ? 1 : 0, modifiers); } @@ -92,7 +92,7 @@ public class CallbackBridge { } public static void sendScroll(double xoffset, double yoffset) { - DEBUG_STRING.append("ScrollX=" + xoffset + ",ScrollY=" + yoffset); + DEBUG_STRING.append("ScrollX=").append(xoffset).append(",ScrollY=").append(yoffset); nativeSendScroll(xoffset, yoffset); } @@ -166,6 +166,30 @@ public class CallbackBridge { return currMods; } + public static void setModifiers(int keyCode, boolean isDown){ + switch (keyCode){ + case LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT: + CallbackBridge.holdingShift = isDown; + return; + + case LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL: + CallbackBridge.holdingCtrl = isDown; + return; + + case LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT: + CallbackBridge.holdingAlt = isDown; + return; + + case LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK: + CallbackBridge.holdingCapslock = isDown; + return; + + case LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK: + CallbackBridge.holdingNumlock = isDown; + return; + } + } + public static native boolean nativeAttachThreadToOther(boolean isAndroid, boolean isUsePushPoll); private static native boolean nativeSendChar(char codepoint); @@ -179,8 +203,6 @@ public class CallbackBridge { private static native void nativeSendScreenSize(int width, int height); public static native boolean nativeIsGrabbing(); - public static native void nativePutControllerAxes(FloatBuffer axBuf); - public static native void nativePutControllerButtons(ByteBuffer axBuf); static { System.loadLibrary("pojavexec"); } diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 32d12c96a..4c53c5055 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -363,43 +363,3 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEn JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(JNIEnv* env, jclass clazz, jlong window) { showingWindow = (long) window; } -JNIEXPORT void JNICALL -Java_org_lwjgl_glfw_CallbackBridge_nativePutControllerAxes(JNIEnv *env, jclass clazz, - jobject ax_buf) { - // TODO: implement nativePutControllerAxes() - if(isInputReady) { - jbyte *src = (jbyte *)((*env)->GetDirectBufferAddress(*env,ax_buf)); - jclass glfw_joystick_class = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID,"org/lwjgl/glfw/GLFW"); - if(glfw_joystick_class == NULL) { - __android_log_print(ANDROID_LOG_ERROR,"ControllerPipeNative","GLFW is not attached!"); - return; - } - jfieldID glfw_controller_axis_data = (*runtimeJNIEnvPtr_ANDROID)->GetStaticFieldID(runtimeJNIEnvPtr_ANDROID,glfw_joystick_class,"joystickData", - "Ljava/nio/FloatBuffer;"); - if(glfw_controller_axis_data == NULL) { - __android_log_print(ANDROID_LOG_ERROR,"ControllerPipeNative","Unable to find the field!"); - return; - } - (*runtimeJNIEnvPtr_ANDROID)->SetStaticObjectField(runtimeJNIEnvPtr_ANDROID,glfw_joystick_class,glfw_controller_axis_data,(*runtimeJNIEnvPtr_ANDROID)->NewDirectByteBuffer(runtimeJNIEnvPtr_ANDROID,src,(*env)->GetDirectBufferCapacity(env,ax_buf))); - } -} -JNIEXPORT void JNICALL -Java_org_lwjgl_glfw_CallbackBridge_nativePutControllerButtons(JNIEnv *env, jclass clazz, - jobject ax_buf) { - // TODO: implement nativePutControllerButtons() - if(isInputReady) { - jbyte *src = (jbyte *)((*env)->GetDirectBufferAddress(*env,ax_buf)); - jclass glfw_joystick_class = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID,"org/lwjgl/glfw/GLFW"); - if(glfw_joystick_class == NULL) { - __android_log_print(ANDROID_LOG_ERROR,"ControllerPipeNative","GLFW is not attached!"); - return; - } - jfieldID glfw_controller_button_data = (*runtimeJNIEnvPtr_ANDROID)->GetStaticFieldID(runtimeJNIEnvPtr_ANDROID,glfw_joystick_class,"buttonData", - "Ljava/nio/ByteBuffer;"); - if(glfw_controller_button_data == NULL) { - __android_log_print(ANDROID_LOG_ERROR,"ControllerPipeNative","Unable to find the field!"); - return; - } - (*runtimeJNIEnvPtr_ANDROID)->SetStaticObjectField(runtimeJNIEnvPtr_ANDROID,glfw_joystick_class,glfw_controller_button_data,(*runtimeJNIEnvPtr_ANDROID)->NewDirectByteBuffer(runtimeJNIEnvPtr_ANDROID,src,(*env)->GetDirectBufferCapacity(env,ax_buf))); - } -} diff --git a/app_pojavlauncher/src/main/res/drawable/control_button_black.xml b/app_pojavlauncher/src/main/res/drawable/control_button_black.xml deleted file mode 100644 index d1d60fa08..000000000 --- a/app_pojavlauncher/src/main/res/drawable/control_button_black.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/drawable/control_button_round.xml b/app_pojavlauncher/src/main/res/drawable/control_button_round.xml deleted file mode 100644 index 50973a575..000000000 --- a/app_pojavlauncher/src/main/res/drawable/control_button_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/drawable/control_button_round_black.xml b/app_pojavlauncher/src/main/res/drawable/control_button_round_black.xml deleted file mode 100644 index e0a801ca8..000000000 --- a/app_pojavlauncher/src/main/res/drawable/control_button_round_black.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/drawable/control_button_round_normal.xml b/app_pojavlauncher/src/main/res/drawable/control_button_round_normal.xml deleted file mode 100644 index 97f91f53d..000000000 --- a/app_pojavlauncher/src/main/res/drawable/control_button_round_normal.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/drawable/control_button_round_pressed.xml b/app_pojavlauncher/src/main/res/drawable/control_button_round_pressed.xml deleted file mode 100644 index d72b64b0b..000000000 --- a/app_pojavlauncher/src/main/res/drawable/control_button_round_pressed.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app_pojavlauncher/src/main/res/drawable/pointer.png b/app_pojavlauncher/src/main/res/drawable/pointer.png new file mode 100644 index 000000000..7ad77f98f Binary files /dev/null and b/app_pojavlauncher/src/main/res/drawable/pointer.png differ diff --git a/app_pojavlauncher/src/main/res/layout/control_button_setting.xml b/app_pojavlauncher/src/main/res/layout/control_button_setting.xml new file mode 100644 index 000000000..d867d183a --- /dev/null +++ b/app_pojavlauncher/src/main/res/layout/control_button_setting.xml @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/layout/control_setting.xml b/app_pojavlauncher/src/main/res/layout/control_setting.xml deleted file mode 100644 index 74841bd43..000000000 --- a/app_pojavlauncher/src/main/res/layout/control_setting.xml +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app_pojavlauncher/src/main/res/layout/main_with_customctrl.xml b/app_pojavlauncher/src/main/res/layout/main_with_customctrl.xml index 608f8d77a..cff6aafc4 100644 --- a/app_pojavlauncher/src/main/res/layout/main_with_customctrl.xml +++ b/app_pojavlauncher/src/main/res/layout/main_with_customctrl.xml @@ -39,6 +39,13 @@ + + + + diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index db2b039af..fc1587910 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -170,18 +170,28 @@ Size Width Height + + Mapping + Orientation + Background color + Corner radius + Stroke width + Stroke color Dynamic position Dynamic X Dynamic Y Background transparency + Button Opacity Key combination Alt Ctrl Shift Add button + Add button drawer + Add sub-button Select default Control json @@ -207,6 +217,7 @@ Mouse Speed Changes the speed of the software mouse Mouse pass-thru + Swipeable Rounded The current amount of free RAM (%d) is lower than allocated RAM (%d), which may lead to crashes. Change the allocation if the game crashes. Memory allocation diff --git a/app_pojavlauncher/src/main/res/xml/pref_main.xml b/app_pojavlauncher/src/main/res/xml/pref_main.xml index 2b5ded16a..ee23eaeb1 100644 --- a/app_pojavlauncher/src/main/res/xml/pref_main.xml +++ b/app_pojavlauncher/src/main/res/xml/pref_main.xml @@ -24,12 +24,6 @@ app2:selectable="false" app2:icon="@drawable/tap_len" /> -