This commit is contained in:
ArtDev
2021-07-26 16:31:37 +03:00
committed by GitHub
46 changed files with 3601 additions and 1942 deletions

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@
/build
/*/build
app_pojavlauncher/src/main/assets/components/jre
local.properties
.idea/
app_pojavlauncher/.cxx/

View File

@@ -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'

View File

@@ -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);
}
}

View File

@@ -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<Integer, Integer> androidToLwjglMap;
public static String[] androidKeyNameArray;
static {
// Mapping Android Keycodes to LWJGL Keycodes
androidToLwjglMap = new ArrayMap<Integer, Integer>();
// 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<String> keyName = new ArrayList<String>();
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;
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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());

View File

@@ -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;
}
}

View File

@@ -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){

View File

@@ -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 <a target="_blank" href="http://www.glfw.org/docs/latest/input.html#input_mouse_button">mouse button input</a> 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,

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<String, String> 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);
}
}

View File

@@ -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<ControlData> 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<ControlData> buttonProperties){
this(buttonProperties, new ControlData("Drawer", new int[] {}, Tools.currentDisplayMetrics.widthPixels/2, Tools.currentDisplayMetrics.heightPixels/2));
}
public ControlDrawerData(ArrayList<ControlData> buttonProperties, ControlData properties){
this(buttonProperties, properties, Orientation.LEFT);
}
public ControlDrawerData(ArrayList<ControlData> buttonProperties, ControlData properties, Orientation orientation){
this.buttonProperties = buttonProperties;
this.properties = properties;
this.orientation = orientation;
}
}

View File

@@ -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<View> 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<ControlButton> getButtonChildren(){
ArrayList<ControlButton> children = new ArrayList<>();
for(int i=0; i<getChildCount(); ++i){
View v = getChildAt(i);
if(v instanceof ControlButton)
children.add(((ControlButton) v));
}
return children;
}
HashMap<View, ControlButton> 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;
}
}

View File

@@ -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<ControlData> mControlDataList;
public List<ControlDrawerData> mDrawerDataList;
public CustomControls() {
this(new ArrayList<ControlData>());
this(new ArrayList<>(), new ArrayList<>());
}
public CustomControls(List<ControlData> mControlDataList) {
public CustomControls(List<ControlData> mControlDataList, List<ControlDrawerData> 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));
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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<ControlSubButton> 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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) );
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<String> adapter = new ArrayAdapter<String>(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 + " %");
}
}

View File

@@ -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<String> 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<spinnersKeycode.length; ++i){
if (spinnersKeycode[i].getSelectedItemPosition() < specialArr.length) {
properties.keycodes[i] = spinnersKeycode[i].getSelectedItemPosition() - specialArr.length;
} else {
properties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(spinnersKeycode[i].getSelectedItemPosition() - specialArr.length);
}
}
properties.opacity = seekBarOpacity.getProgress()/100f;
properties.strokeWidth = seekBarStrokeWidth.getProgress();
properties.cornerRadius = seekBarCornerRadius.getProgress();
properties.bgColor = ((ColorDrawable)buttonBackgroundColor.getDrawable()).getColor();
properties.strokeColor = ((ColorDrawable) buttonStrokeColor.getDrawable()).getColor();
properties.isToggle = checkToggle.isChecked();
properties.passThruEnabled = checkPassThrough.isChecked();
properties.isSwipeable = checkBoxSwipeable.isChecked();
properties.setWidth(Float.parseFloat(editWidth.getText().toString()));
properties.setHeight(Float.parseFloat(editHeight.getText().toString()));
properties.isDynamicBtn = checkDynamicPosition.isChecked();
properties.dynamicX = editDynamicX.getText().toString().isEmpty() ? properties.dynamicX = Float.toString(properties.x) : editDynamicX.getText().toString();
properties.dynamicY = editDynamicY.getText().toString().isEmpty() ? properties.dynamicY = Float.toString(properties.y) : editDynamicY.getText().toString();
button.updateProperties();
}
}

View File

@@ -0,0 +1,75 @@
package net.kdt.pojavlaunch.customcontrols.handleview;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
public class EditControlDrawerPopup extends EditControlButtonPopup{
private Spinner spinnerOrientation;
private ControlDrawer drawer;
private ControlDrawerData drawerData;
public EditControlDrawerPopup(ControlDrawer editedButton) {
super(editedButton);
drawer = editedButton;
drawerData = editedButton.getDrawerData();
}
@Override
protected void hideUselessViews() {
(v.findViewById(R.id.editMapping_textView)).setVisibility(View.GONE);
checkPassThrough.setVisibility(View.GONE);
checkToggle.setVisibility(View.GONE);
checkBoxSwipeable.setVisibility(View.GONE);
}
@Override
protected void initializeEditDialog(Context ctx) {
super.initializeEditDialog(ctx);
spinnerOrientation = v.findViewById(R.id.editOrientation_spinner);
ArrayAdapter<ControlDrawerData.Orientation> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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)));
}
}

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#4D000000" />
<padding android:left="8.0dip" android:top="0.0dip" android:right="8.0dip" android:bottom="0.0dip" />
</shape>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/control_button_round_pressed" />
<item android:drawable="@drawable/control_button_round_normal" />
</selector>

View File

@@ -1,5 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#4D000000" />
<corners android:radius="6dp" />
<padding android:left="8.0dip" android:top="0.0dip" android:right="8.0dip" android:bottom="0.0dip" />
</shape>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#807f7f7f" />
<stroke android:width="2.0dip" android:color="#dd7f7f7f" />
<corners android:radius="6dp" />
<padding android:left="8.0dip" android:top="0.0dip" android:right="8.0dip" android:bottom="0.0dip" />
</shape>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#dd7f7f7f" />
<stroke android:width="2.0dip" android:color="#dd7f7f7f" />
<corners android:radius="6dp" />
<padding android:left="8.0dip" android:top="0.0dip" android:right="8.0dip" android:bottom="0.0dip" />
</shape>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

View File

@@ -0,0 +1,459 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kdt.DefocusableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="500dp"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_optimizationLevel="standard|dimensions|chains">
<!-- EDIT NAME SECTION -->
<TextView
android:id="@+id/editName_textView"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="@string/global_name"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<EditText
android:id="@+id/editName_editText"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="@+id/editName_textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/editName_textView"
app:layout_constraintBottom_toBottomOf="@+id/editName_textView"
/>
<!-- SIZE SECTION -->
<TextView
android:id="@+id/editSize_textView"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:gravity="center"
android:text="@string/customctrl_size"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editName_textView"
tools:visibility="visible" />
<EditText
android:id="@+id/editSize_editTextX"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="@id/editSize_textView"
app:layout_constraintTop_toTopOf="@id/editSize_textView"
app:layout_constraintBottom_toBottomOf="@id/editSize_textView"
app:layout_constraintEnd_toStartOf="@id/editSize_editTextY"/>
<EditText
android:id="@+id/editSize_editTextY"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="@id/editSize_editTextX"
app:layout_constraintTop_toTopOf="@id/editSize_textView"
app:layout_constraintBottom_toBottomOf="@id/editSize_textView"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="x"
android:gravity="center"
app:layout_constraintStart_toEndOf="@id/editSize_editTextX"
app:layout_constraintEnd_toStartOf="@id/editSize_editTextY"
app:layout_constraintTop_toTopOf="@id/editSize_textView"
app:layout_constraintBottom_toBottomOf="@id/editSize_textView" />
<!-- MAPPING SECTION -->
<TextView
android:id="@+id/editMapping_textView"
android:layout_width="wrap_content"
android:layout_height="70dp"
android:text="@string/customctrl_mapping"
android:paddingTop="8dp"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editSize_textView"/>
<Spinner
android:id="@+id/editMapping_spinner_1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintStart_toEndOf="@id/editMapping_textView"
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_2"
app:layout_constraintBottom_toTopOf="@id/editMapping_spinner_3"/>
<TextView
android:id="@+id/editMapping_plus_1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="+"
android:gravity="center"
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_1"
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_2"
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
app:layout_constraintBottom_toBottomOf="@id/editMapping_spinner_1"
/>
<Spinner
android:id="@+id/editMapping_spinner_2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
app:layout_constraintBottom_toBottomOf="@id/editMapping_spinner_1"
/>
<TextView
android:id="@+id/editMapping_plus_2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="+"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
app:layout_constraintEnd_toEndOf="@id/editMapping_textView"
app:layout_constraintTop_toTopOf="@id/editMapping_spinner_3"
/>
<Spinner
android:id="@+id/editMapping_spinner_3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintStart_toEndOf="@id/editMapping_textView"
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_1"
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_4"/>
<TextView
android:id="@+id/editMapping_plus_3"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="+"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_3"
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_4"
app:layout_constraintTop_toTopOf="@id/editMapping_spinner_4"
/>
<Spinner
android:id="@+id/editMapping_spinner_4"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_3"
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
/>
<!-- ORIENTATION SECTION -->
<TextView
android:id="@+id/editOrientation_textView"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="@string/customctrl_orientation"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editMapping_textView"
/>
<Spinner
android:id="@+id/editOrientation_spinner"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintStart_toEndOf="@id/editOrientation_textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editOrientation_textView"
app:layout_constraintBottom_toBottomOf="@id/editOrientation_textView"
/>
<!-- TOGGLE SECTION -->
<CheckBox
android:id="@+id/checkboxToggle"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_toggle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editOrientation_textView"
/>
<!-- MOUSE PASS THROUGH SECTION -->
<CheckBox
android:id="@+id/checkboxPassThrough"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/customctrl_passthru"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/checkboxToggle"
/>
<!-- SWIPEABLE BUTTON SECTION -->
<CheckBox
android:id="@+id/checkboxSwipeable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/customctrl_swipeable"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/checkboxPassThrough"
/>
<!-- BACKGROUND COLOR SECTION -->
<TextView
android:id="@+id/editBackgroundColor_textView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:text="@string/customctrl_background_color"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/checkboxSwipeable"
/>
<ImageButton
android:id="@+id/editBackgroundColor_imageButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="50dp"
android:layout_marginVertical="5dp"
android:background="#FFFFFFFF"
app:layout_constraintStart_toEndOf="@id/editBackgroundColor_textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editBackgroundColor_textView"
app:layout_constraintBottom_toBottomOf="@id/editBackgroundColor_textView"
/>
<!-- STROKE WIDTH -->
<TextView
android:id="@+id/editStrokeWidth_textView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:text="@string/customctrl_stroke_width"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editBackgroundColor_textView"/>
<SeekBar
android:id="@+id/editStrokeWidth_seekbar"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="@id/editStrokeWidth_textView"
app:layout_constraintTop_toTopOf="@id/editStrokeWidth_textView"
app:layout_constraintBottom_toBottomOf="@id/editStrokeWidth_textView"
app:layout_constraintEnd_toStartOf="@id/editStrokeWidth_textView_percent"
/>
<TextView
android:id="@+id/editStrokeWidth_textView_percent"
android:layout_width="50dp"
android:layout_height="0dp"
android:text="100%"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editStrokeWidth_textView"
app:layout_constraintBottom_toBottomOf="@id/editStrokeWidth_textView"
/>
<!-- STROKE COLOR VERSION -->
<TextView
android:id="@+id/editStrokeColor_textView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:text="@string/customctrl_stroke_color"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editStrokeWidth_textView"
/>
<ImageButton
android:id="@+id/editStrokeColor_imageButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="50dp"
android:layout_marginVertical="5dp"
android:background="#FFFFFFFF"
app:layout_constraintStart_toEndOf="@id/editStrokeColor_textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editStrokeColor_textView"
app:layout_constraintBottom_toBottomOf="@id/editStrokeColor_textView"
/>
<!-- CORNER RADIUS SECTION -->
<TextView
android:id="@+id/editCornerRadius_textView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:text="@string/customctrl_corner_radius"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editStrokeColor_textView"/>
<SeekBar
android:id="@+id/editCornerRadius_seekbar"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="@id/editCornerRadius_textView"
app:layout_constraintTop_toTopOf="@id/editCornerRadius_textView"
app:layout_constraintBottom_toBottomOf="@id/editCornerRadius_textView"
app:layout_constraintEnd_toStartOf="@id/editCornerRadius_textView_percent"
/>
<TextView
android:id="@+id/editCornerRadius_textView_percent"
android:layout_width="50dp"
android:layout_height="0dp"
android:text="100%"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editCornerRadius_textView"
app:layout_constraintBottom_toBottomOf="@id/editCornerRadius_textView"
/>
<!-- BUTTON OPACITY SECTION -->
<TextView
android:id="@+id/editButtonOpacity_textView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:text="@string/customctrl_button_opacity"
android:gravity="center"
android:paddingEnd="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editCornerRadius_textView"/>
<SeekBar
android:id="@+id/editButtonOpacity_seekbar"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toEndOf="@id/editButtonOpacity_textView"
app:layout_constraintTop_toTopOf="@id/editButtonOpacity_textView"
app:layout_constraintBottom_toBottomOf="@id/editButtonOpacity_textView"
app:layout_constraintEnd_toStartOf="@id/editButtonOpacity_textView_percent"
/>
<TextView
android:id="@+id/editButtonOpacity_textView_percent"
android:layout_width="50dp"
android:layout_height="0dp"
android:text="100%"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/editButtonOpacity_textView"
app:layout_constraintBottom_toBottomOf="@id/editButtonOpacity_textView"
/>
<!-- DYNAMIC BUTTON SECTION -->
<CheckBox
android:id="@+id/checkboxDynamicPosition"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_dynamicpos"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editButtonOpacity_textView"
/>
<TextView
android:id="@+id/editDynamicPositionX_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/customctrl_dynamicpos_x"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/checkboxDynamicPosition"
/>
<EditText
android:id="@+id/editDynamicPositionX_editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionX_textView"
/>
<TextView
android:id="@+id/editDynamicPositionY_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/customctrl_dynamicpos_y"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionX_editText"
/>
<EditText
android:id="@+id/editDynamicPositionY_editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionY_textView"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.kdt.DefocusableScrollView>

View File

@@ -1,158 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/customctrl_keyname"/>
<Spinner
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/controlsetting_spinner_lwjglkeycode"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/global_name"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:singleLine="true"
android:id="@+id/controlsetting_edit_name"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/customctrl_transparency_bg"/>
<SeekBar
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/controlsetting_seek_transparency"/>
<CheckBox
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_toggle"
android:id="@+id/controlsetting_checkbox_toggle"/>
<CheckBox
android:id="@+id/controlsetting_checkbox_passthru"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/customctrl_passthru" />
<CheckBox
android:id="@+id/controlsetting_checkbox_round"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/customctrl_rounded" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/customctrl_size"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:id="@+id/controlsetting_edit_width"
android:hint="@string/customctrl_size_width"
android:inputType="numberDecimal"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="×"
android:gravity="center"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:id="@+id/controlsetting_edit_height"
android:hint="@string/customctrl_size_height"
android:inputType="numberDecimal"/>
</LinearLayout>
<CheckBox
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_dynamicpos"
android:id="@+id/controlsetting_checkbox_dynamicpos"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/customctrl_dynamicpos_x"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:singleLine="true"
android:id="@+id/controlsetting_edit_dynamicpos_x"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/customctrl_dynamicpos_y"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:singleLine="true"
android:id="@+id/controlsetting_edit_dynamicpos_y"/>
</LinearLayout>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/customctrl_keycombine"/>
<CheckBox
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_keycombine_alt"
android:id="@+id/controlsetting_checkbox_keycombine_alt"/>
<CheckBox
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_keycombine_control"
android:id="@+id/controlsetting_checkbox_keycombine_control"/>
<CheckBox
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/customctrl_keycombine_shift"
android:id="@+id/controlsetting_checkbox_keycombine_shift"/>
</LinearLayout>
</ScrollView>

View File

@@ -39,6 +39,13 @@
</LinearLayout>
<ImageView
android:id="@+id/console_pointer"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/pointer" />
</net.kdt.pojavlaunch.customcontrols.ControlLayout>
<LinearLayout

View File

@@ -3,6 +3,10 @@
android:id="@+id/menu_ctrl_add"
android:title="@string/customctrl_addbutton"/>
<item
android:id="@+id/menu_ctrl_add_drawer"
android:title="@string/customctrl_addbutton_drawer"/>
<item
android:id="@+id/menu_ctrl_load"
android:title="@string/global_load"/>

View File

@@ -170,18 +170,28 @@
<string name="customctrl_size">Size</string>
<string name="customctrl_size_width">Width</string>
<string name="customctrl_size_height">Height</string>
<string name="customctrl_mapping">Mapping</string>
<string name="customctrl_orientation">Orientation</string>
<string name="customctrl_background_color">Background color</string>
<string name="customctrl_corner_radius">Corner radius</string>
<string name="customctrl_stroke_width">Stroke width</string>
<string name="customctrl_stroke_color">Stroke color</string>
<string name="customctrl_dynamicpos">Dynamic position</string>
<string name="customctrl_dynamicpos_x">Dynamic X</string>
<string name="customctrl_dynamicpos_y">Dynamic Y</string>
<string name="customctrl_transparency_bg">Background transparency</string>
<string name="customctrl_button_opacity">Button Opacity</string>
<string name="customctrl_keycombine">Key combination</string>
<string name="customctrl_keycombine_alt">Alt</string>
<string name="customctrl_keycombine_control">Ctrl</string>
<string name="customctrl_keycombine_shift">Shift</string>
<string name="customctrl_addbutton">Add button</string>
<string name="customctrl_addbutton_drawer">Add button drawer</string>
<string name="customctrl_addsubbutton">Add sub-button</string>
<string name="customctrl_selectdefault">Select default Control json</string>
@@ -207,6 +217,7 @@
<string name="mcl_setting_title_mousespeed">Mouse Speed</string>
<string name="mcl_setting_subtitle_mousespeed">Changes the speed of the software mouse</string>
<string name="customctrl_passthru">Mouse pass-thru</string>
<string name="customctrl_swipeable">Swipeable</string>
<string name="customctrl_rounded">Rounded</string>
<string name="memory_warning_msg">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.</string>
<string name="mcl_memory_allocation">Memory allocation</string>

View File

@@ -24,12 +24,6 @@
app2:selectable="false"
app2:icon="@drawable/tap_len" />
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="flatButtonStyle"
android:summary="@string/mcl_setting_subtitle_flat_button_style"
android:title="@string/mcl_setting_title_flat_button_style"
app2:icon="@drawable/ic_flatstyle" />
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"