Merge pull request #2917 from PojavLauncherTeam/merge-profiles
Merge and resolve conflicts
@@ -108,3 +108,4 @@ Any code change should be submitted as a pull request. The description should ex
|
||||
- [xHook](https://github.com/iqiyi/xHook) (Used for exit code trapping): [MIT and BSD-style licenses](https://github.com/iqiyi/xHook/blob/master/LICENSE).
|
||||
- [libepoxy](https://github.com/anholt/libepoxy): [MIT License](https://github.com/anholt/libepoxy/blob/master/COPYING).
|
||||
- [virglrenderer](https://github.com/PojavLauncherTeam/virglrenderer): [MIT License](https://gitlab.freedesktop.org/virgl/virglrenderer/-/blob/master/COPYING).
|
||||
- Thanks to [MCHeads](https://mc-heads.net) for providing Minecraft avatars.
|
||||
|
||||
@@ -59,12 +59,12 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:theme="@style/MenuDialog"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".FatalErrorActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
|
||||
<activity
|
||||
android:theme="@style/MenuDialog"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".ExitActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
|
||||
|
||||
@@ -1 +1 @@
|
||||
20211115
|
||||
20220304
|
||||
|
||||
@@ -5,15 +5,15 @@ import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
/**
|
||||
Class allowing to ignore the focusing from an item such an EditText within it.
|
||||
Ignoring it will stop the scrollView from refocusing on the view
|
||||
*/
|
||||
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;
|
||||
|
||||
private boolean mKeepFocusing = false;
|
||||
|
||||
|
||||
public DefocusableScrollView(Context context) {
|
||||
@@ -33,16 +33,16 @@ public class DefocusableScrollView extends ScrollView {
|
||||
}
|
||||
|
||||
public void setKeepFocusing(boolean shouldKeepFocusing){
|
||||
keepFocusing = shouldKeepFocusing;
|
||||
mKeepFocusing = shouldKeepFocusing;
|
||||
}
|
||||
|
||||
public boolean isKeepFocusing(){
|
||||
return keepFocusing;
|
||||
return mKeepFocusing;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
||||
if(!keepFocusing) return 0;
|
||||
if(!mKeepFocusing) return 0;
|
||||
return super.computeScrollDeltaToGetChildRectOnScreen(rect);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ import net.kdt.pojavlaunch.R;
|
||||
* It has support for the Logger class
|
||||
*/
|
||||
public class LoggerView extends ConstraintLayout {
|
||||
private Logger.eventLogListener logListener;
|
||||
private ToggleButton toggleButton;
|
||||
private ScrollView scrollView;
|
||||
private TextView log;
|
||||
private Logger.eventLogListener mLogListener;
|
||||
private ToggleButton mToggleButton;
|
||||
private ScrollView mScrollView;
|
||||
private TextView mLogTextView;
|
||||
|
||||
|
||||
public LoggerView(@NonNull Context context) {
|
||||
@@ -36,50 +36,51 @@ public class LoggerView extends ConstraintLayout {
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
super.setVisibility(visibility);
|
||||
// Triggers the log view shown state by default when viewing it
|
||||
mToggleButton.setChecked(visibility == VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate the layout, and add component behaviors
|
||||
*/
|
||||
private void init(){
|
||||
inflate(getContext(), R.layout.loggerview_layout, this);
|
||||
log = findViewById(R.id.content_log_view);
|
||||
log.setTypeface(Typeface.MONOSPACE);
|
||||
inflate(getContext(), R.layout.view_logger, this);
|
||||
mLogTextView = findViewById(R.id.content_log_view);
|
||||
mLogTextView.setTypeface(Typeface.MONOSPACE);
|
||||
//TODO clamp the max text so it doesn't go oob
|
||||
log.setMaxLines(Integer.MAX_VALUE);
|
||||
log.setEllipsize(null);
|
||||
log.setVisibility(GONE);
|
||||
mLogTextView.setMaxLines(Integer.MAX_VALUE);
|
||||
mLogTextView.setEllipsize(null);
|
||||
mLogTextView.setVisibility(GONE);
|
||||
|
||||
// Toggle log visibility
|
||||
toggleButton = findViewById(R.id.content_log_toggle_log);
|
||||
toggleButton.setOnCheckedChangeListener(
|
||||
mToggleButton = findViewById(R.id.content_log_toggle_log);
|
||||
mToggleButton.setOnCheckedChangeListener(
|
||||
(compoundButton, isChecked) -> {
|
||||
log.setVisibility(isChecked ? VISIBLE : GONE);
|
||||
if(!isChecked) log.setText("");
|
||||
mLogTextView.setVisibility(isChecked ? VISIBLE : GONE);
|
||||
if(!isChecked) mLogTextView.setText("");
|
||||
});
|
||||
toggleButton.setChecked(false);
|
||||
mToggleButton.setChecked(false);
|
||||
|
||||
// Remove the loggerView from the user View
|
||||
ImageButton cancelButton = findViewById(R.id.log_view_cancel);
|
||||
cancelButton.setOnClickListener(view -> LoggerView.this.setVisibility(GONE));
|
||||
|
||||
// Set the scroll view
|
||||
scrollView = findViewById(R.id.content_log_scroll);
|
||||
mScrollView = findViewById(R.id.content_log_scroll);
|
||||
|
||||
// Listen to logs
|
||||
logListener = text -> {
|
||||
if(log.getVisibility() != VISIBLE) return;
|
||||
mLogListener = text -> {
|
||||
if(mLogTextView.getVisibility() != VISIBLE) return;
|
||||
post(() -> {
|
||||
log.append(text + '\n');
|
||||
scrollView.fullScroll(View.FOCUS_DOWN);
|
||||
mLogTextView.append(text + '\n');
|
||||
mScrollView.fullScroll(View.FOCUS_DOWN);
|
||||
});
|
||||
|
||||
};
|
||||
Logger.getInstance().setLogListener(logListener);
|
||||
Logger.getInstance().setLogListener(mLogListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
super.setVisibility(visibility);
|
||||
// Triggers the log view shown state by default when viewing it
|
||||
toggleButton.setChecked(visibility == VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
|
||||
public class MineButton extends androidx.appcompat.widget.AppCompatButton
|
||||
{
|
||||
public class MineButton extends androidx.appcompat.widget.AppCompatButton {
|
||||
|
||||
public MineButton(Context ctx) {
|
||||
this(ctx, null);
|
||||
|
||||
@@ -4,22 +4,18 @@ import android.content.*;
|
||||
import android.util.*;
|
||||
import android.graphics.*;
|
||||
|
||||
public class MineEditText extends com.google.android.material.textfield.TextInputEditText
|
||||
{
|
||||
public MineEditText(Context ctx)
|
||||
{
|
||||
public class MineEditText extends com.google.android.material.textfield.TextInputEditText {
|
||||
public MineEditText(Context ctx) {
|
||||
super(ctx);
|
||||
init();
|
||||
}
|
||||
|
||||
public MineEditText(Context ctx, AttributeSet attrs)
|
||||
{
|
||||
public MineEditText(Context ctx, AttributeSet attrs) {
|
||||
super(ctx, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
public void init() {
|
||||
setBackgroundColor(Color.parseColor("#131313"));
|
||||
setPadding(5, 5, 5, 5);
|
||||
}
|
||||
|
||||
@@ -10,56 +10,20 @@ import net.kdt.pojavlaunch.utils.*;
|
||||
import org.lwjgl.glfw.*;
|
||||
|
||||
public class AWTCanvasView extends TextureView implements TextureView.SurfaceTextureListener, Runnable {
|
||||
private final int MAX_SIZE = 100;
|
||||
private final double NANOS = 1000000000.0;
|
||||
|
||||
private int mScaleFactor;
|
||||
private int[] mScales;
|
||||
|
||||
private int mWidth, mHeight;
|
||||
private boolean mIsDestroyed = false;
|
||||
|
||||
private TextPaint fpsPaint;
|
||||
private boolean attached = false;
|
||||
private final TextPaint mFpsPaint;
|
||||
private boolean mAttached = false;
|
||||
private boolean mDrawing;
|
||||
|
||||
// Temporary count fps https://stackoverflow.com/a/13729241
|
||||
private LinkedList<Long> times = new LinkedList<Long>(){{add(System.nanoTime());}};
|
||||
private final int MAX_SIZE = 100;
|
||||
private final double NANOS = 1000000000.0;
|
||||
|
||||
/** Calculates and returns frames per second */
|
||||
private double fps() {
|
||||
long lastTime = System.nanoTime();
|
||||
double difference = (lastTime - times.getFirst()) / NANOS;
|
||||
times.addLast(lastTime);
|
||||
int size = times.size();
|
||||
if (size > MAX_SIZE) {
|
||||
times.removeFirst();
|
||||
}
|
||||
return difference > 0 ? times.size() / difference : 0.0;
|
||||
}
|
||||
|
||||
/** Computes the scale to better fit the screen */
|
||||
void initScaleFactors(){
|
||||
initScaleFactors(0);
|
||||
}
|
||||
|
||||
void initScaleFactors(int forcedScale){
|
||||
//Could be optimized
|
||||
if(forcedScale < 1) { //Auto scale
|
||||
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
|
||||
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
|
||||
}else{
|
||||
mScaleFactor = forcedScale;
|
||||
}
|
||||
|
||||
int[] scales = new int[2]; //Left, Top
|
||||
|
||||
scales[0] = (CallbackBridge.physicalWidth/2);
|
||||
scales[0] -= scales[0]/mScaleFactor;
|
||||
|
||||
scales[1] = (CallbackBridge.physicalHeight/2);
|
||||
scales[1] -= scales[1]/mScaleFactor;
|
||||
|
||||
mScales = scales;
|
||||
}
|
||||
private final LinkedList<Long> mTimes = new LinkedList<Long>(){{add(System.nanoTime());}};
|
||||
|
||||
public AWTCanvasView(Context ctx) {
|
||||
this(ctx, null);
|
||||
@@ -67,11 +31,10 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
|
||||
|
||||
public AWTCanvasView(Context ctx, AttributeSet attrs) {
|
||||
super(ctx, attrs);
|
||||
// setWillNotDraw(false);
|
||||
|
||||
fpsPaint = new TextPaint();
|
||||
fpsPaint.setColor(Color.WHITE);
|
||||
fpsPaint.setTextSize(20);
|
||||
mFpsPaint = new TextPaint();
|
||||
mFpsPaint.setColor(Color.WHITE);
|
||||
mFpsPaint.setTextSize(20);
|
||||
|
||||
setSurfaceTextureListener(this);
|
||||
initScaleFactors();
|
||||
@@ -101,21 +64,19 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
||||
}
|
||||
|
||||
private boolean mDrawing;
|
||||
private Surface mSurface;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Canvas canvas;
|
||||
mSurface = new Surface(getSurfaceTexture());
|
||||
Surface surface = new Surface(getSurfaceTexture());
|
||||
|
||||
try {
|
||||
while (!mIsDestroyed && mSurface.isValid()) {
|
||||
canvas = mSurface.lockCanvas(null);
|
||||
while (!mIsDestroyed && surface.isValid()) {
|
||||
canvas = surface.lockCanvas(null);
|
||||
canvas.drawRGB(0, 0, 0);
|
||||
|
||||
if (!attached) {
|
||||
attached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
|
||||
if (!mAttached) {
|
||||
mAttached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
|
||||
} else {
|
||||
int[] rgbArray = JREUtils.renderAWTScreenFrame(/* canvas, mWidth, mHeight */);
|
||||
mDrawing = rgbArray != null;
|
||||
@@ -123,22 +84,55 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
|
||||
|
||||
canvas.save();
|
||||
canvas.scale(mScaleFactor, mScaleFactor);
|
||||
canvas.translate(-mScales[0],-mScales[1]);
|
||||
|
||||
canvas.translate(-mScales[0], -mScales[1]);
|
||||
|
||||
canvas.drawBitmap(rgbArray, 0, CallbackBridge.physicalWidth, 0, 0, CallbackBridge.physicalWidth, CallbackBridge.physicalHeight, true, null);
|
||||
canvas.restore();
|
||||
|
||||
}
|
||||
rgbArray = null;
|
||||
// System.gc();
|
||||
}
|
||||
canvas.drawText("FPS: " + (Math.round(fps() * 10) / 10) + ", attached=" + attached + ", drawing=" + mDrawing, 50, 50, fpsPaint);
|
||||
|
||||
mSurface.unlockCanvasAndPost(canvas);
|
||||
canvas.drawText("FPS: " + (Math.round(fps() * 10) / 10) + ", attached=" + mAttached + ", drawing=" + mDrawing, 50, 50, mFpsPaint);
|
||||
surface.unlockCanvasAndPost(canvas);
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(getContext(), th);
|
||||
} catch (Throwable throwable) {
|
||||
Tools.showError(getContext(), throwable);
|
||||
}
|
||||
surface.release();
|
||||
}
|
||||
|
||||
/** Computes the scale to better fit the screen */
|
||||
void initScaleFactors(){
|
||||
initScaleFactors(0);
|
||||
}
|
||||
|
||||
void initScaleFactors(int forcedScale){
|
||||
//Could be optimized
|
||||
if(forcedScale < 1) { //Auto scale
|
||||
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
|
||||
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
|
||||
}else{
|
||||
mScaleFactor = forcedScale;
|
||||
}
|
||||
|
||||
int[] scales = new int[2]; //Left, Top
|
||||
|
||||
scales[0] = (CallbackBridge.physicalWidth/2);
|
||||
scales[0] -= scales[0]/mScaleFactor;
|
||||
|
||||
scales[1] = (CallbackBridge.physicalHeight/2);
|
||||
scales[1] -= scales[1]/mScaleFactor;
|
||||
|
||||
mScales = scales;
|
||||
}
|
||||
|
||||
/** Calculates and returns frames per second */
|
||||
private double fps() {
|
||||
long lastTime = System.nanoTime();
|
||||
double difference = (lastTime - mTimes.getFirst()) / NANOS;
|
||||
mTimes.addLast(lastTime);
|
||||
int size = mTimes.size();
|
||||
if (size > MAX_SIZE) {
|
||||
mTimes.removeFirst();
|
||||
}
|
||||
return difference > 0 ? mTimes.size() / difference : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ package net.kdt.pojavlaunch;
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
public class AWTInputEvent
|
||||
{
|
||||
public class AWTInputEvent {
|
||||
// InputEvent
|
||||
/**
|
||||
* This flag indicates that the Shift key was down when the event
|
||||
|
||||
@@ -7,8 +7,7 @@ import net.kdt.pojavlaunch.utils.*;
|
||||
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_IGNORE_NOTCH;
|
||||
|
||||
public class BaseActivity extends AppCompatActivity
|
||||
{
|
||||
public abstract class BaseActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -24,7 +23,7 @@ public class BaseActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void startActivity(Intent i) {
|
||||
super.startActivity(i);
|
||||
new Throwable("StartActivity").printStackTrace();
|
||||
//new Throwable("StartActivity").printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,22 +4,16 @@ import static net.kdt.pojavlaunch.Tools.getFileName;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.*;
|
||||
import android.text.method.*;
|
||||
import android.view.*;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.*;
|
||||
import com.kdt.pickafile.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import net.kdt.pojavlaunch.extra.ExtraCore;
|
||||
import net.kdt.pojavlaunch.extra.ExtraListener;
|
||||
import net.kdt.pojavlaunch.fragments.*;
|
||||
@@ -74,7 +68,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
|
||||
|
||||
public static final int RUN_MOD_INSTALLER = 2050;
|
||||
private void installMod(boolean customJavaArgs) {
|
||||
if (MultiRTUtils.getExactJREName(8) == null) {
|
||||
if (MultiRTUtils.getExactJreName(8) == null) {
|
||||
Toast.makeText(this, R.string.multirt_nojava8rt, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
@@ -118,6 +112,19 @@ public abstract class BaseLauncherActivity extends BaseActivity {
|
||||
if (LauncherProfiles.mainProfileJson != null && LauncherProfiles.mainProfileJson.profiles != null && LauncherProfiles.mainProfileJson.profiles.containsKey(mProfile.selectedProfile + "")) {
|
||||
MinecraftProfile prof = LauncherProfiles.mainProfileJson.profiles.get(mProfile.selectedProfile + "");
|
||||
if (prof != null && prof.lastVersionId != null) {
|
||||
if (mProfile.accessToken.equals("0")) {
|
||||
File verJsonFile = new File(Tools.DIR_HOME_VERSION,
|
||||
mProfile.selectedVersion + "/" + mProfile.selectedVersion + ".json");
|
||||
if (verJsonFile.exists()) {
|
||||
mTask.onPostExecute(null);
|
||||
} else {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.global_error)
|
||||
.setMessage(R.string.mcl_launch_error_localmode)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
mTask.execute(getVersionId(prof.lastVersionId));
|
||||
}
|
||||
}
|
||||
@@ -300,7 +307,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
|
||||
BaseLauncherActivity.this.runOnUiThread(() -> {
|
||||
barrier.dismiss();
|
||||
mRuntimeConfigDialog.refresh();
|
||||
mRuntimeConfigDialog.dialog.show();
|
||||
mRuntimeConfigDialog.mDialog.show();
|
||||
});
|
||||
});
|
||||
t.start();
|
||||
|
||||
@@ -11,7 +11,6 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
@@ -178,17 +177,31 @@ public class BaseMainActivity extends BaseActivity {
|
||||
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
final View decorView = getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_HOVERED, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (CallbackBridge.isGrabbing()){
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
|
||||
}
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_HOVERED, 0);
|
||||
mIsResuming = false;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 0);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
public static void fullyExit() {
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
}
|
||||
@@ -217,6 +230,7 @@ public class BaseMainActivity extends BaseActivity {
|
||||
((mVersionInfo.inheritsFrom == null || mVersionInfo.inheritsFrom.equals(mVersionInfo.id)) ?
|
||||
"" : " (" + mVersionInfo.inheritsFrom + ")"));
|
||||
|
||||
|
||||
JREUtils.redirectAndPrintJRELog(this);
|
||||
if(!LauncherPreferences.PREF_ENABLE_PROFILES){
|
||||
Tools.launchMinecraft(this, mProfile, mProfile.selectedVersion);
|
||||
@@ -225,7 +239,6 @@ public class BaseMainActivity extends BaseActivity {
|
||||
Tools.launchMinecraft(this, mProfile, BaseLauncherActivity.getVersionId(
|
||||
LauncherProfiles.mainProfileJson.profiles.get(mProfile.selectedProfile).lastVersionId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkJavaArgsIsLaunchable(String jreVersion) throws Throwable {
|
||||
@@ -347,7 +360,7 @@ public class BaseMainActivity extends BaseActivity {
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && !touchCharInput.isEnabled()) {
|
||||
if(event.getAction() != KeyEvent.ACTION_UP) return true; // We eat it anyway
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
@@ -362,7 +375,7 @@ public class BaseMainActivity extends BaseActivity {
|
||||
public void adjustMouseSpeedLive() {
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.setTitle(R.string.mcl_setting_title_mousespeed);
|
||||
View v = LayoutInflater.from(this).inflate(R.layout.live_mouse_speed_editor,null);
|
||||
View v = LayoutInflater.from(this).inflate(R.layout.dialog_live_mouse_speed_editor,null);
|
||||
final SeekBar sb = v.findViewById(R.id.mouseSpeed);
|
||||
final TextView tv = v.findViewById(R.id.mouseSpeedTV);
|
||||
sb.setMax(275);
|
||||
|
||||
@@ -5,13 +5,13 @@ import android.content.*;
|
||||
import android.os.*;
|
||||
|
||||
import androidx.appcompat.app.*;
|
||||
import androidx.preference.*;
|
||||
import android.view.*;
|
||||
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.kdt.pickafile.*;
|
||||
import java.io.*;
|
||||
|
||||
@@ -19,18 +19,13 @@ import net.kdt.pojavlaunch.prefs.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.*;
|
||||
|
||||
|
||||
|
||||
public class CustomControlsActivity extends BaseActivity
|
||||
{
|
||||
private DrawerLayout drawerLayout;
|
||||
private NavigationView navDrawer;
|
||||
private ControlLayout ctrlLayout;
|
||||
|
||||
private SharedPreferences mPref;
|
||||
public class CustomControlsActivity extends BaseActivity {
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private NavigationView mDrawerNavigationView;
|
||||
private ControlLayout mControlLayout;
|
||||
|
||||
public boolean isModified = false;
|
||||
public boolean isFromMainActivity = false;
|
||||
private static String selectedName = "new_control";
|
||||
private static String sSelectedName = "new_control";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -41,48 +36,41 @@ public class CustomControlsActivity extends BaseActivity
|
||||
// setTheme(androidx.appcompat.R.style.Theme_AppCompat_Translucent);
|
||||
}
|
||||
|
||||
setContentView(R.layout.control_mapping);
|
||||
|
||||
mPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
setContentView(R.layout.activity_custom_controls);
|
||||
|
||||
ctrlLayout = (ControlLayout) findViewById(R.id.customctrl_controllayout);
|
||||
mControlLayout = (ControlLayout) findViewById(R.id.customctrl_controllayout);
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.customctrl_drawerlayout);
|
||||
mDrawerNavigationView = (NavigationView) findViewById(R.id.customctrl_navigation_view);
|
||||
|
||||
// Menu
|
||||
drawerLayout = (DrawerLayout) findViewById(R.id.customctrl_drawerlayout);
|
||||
|
||||
navDrawer = (NavigationView) findViewById(R.id.customctrl_navigation_view);
|
||||
navDrawer.setNavigationItemSelectedListener(
|
||||
new NavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem menuItem) {
|
||||
mDrawerNavigationView.setNavigationItemSelectedListener(
|
||||
menuItem -> {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.menu_ctrl_load:
|
||||
load(ctrlLayout);
|
||||
load(mControlLayout);
|
||||
break;
|
||||
case R.id.menu_ctrl_add:
|
||||
ctrlLayout.addControlButton(new ControlData("New"));
|
||||
mControlLayout.addControlButton(new ControlData("New"));
|
||||
break;
|
||||
case R.id.menu_ctrl_add_drawer:
|
||||
ctrlLayout.addDrawer(new ControlDrawerData());
|
||||
mControlLayout.addDrawer(new ControlDrawerData());
|
||||
break;
|
||||
case R.id.menu_ctrl_selectdefault:
|
||||
dialogSelectDefaultCtrl(ctrlLayout);
|
||||
dialogSelectDefaultCtrl(mControlLayout);
|
||||
break;
|
||||
case R.id.menu_ctrl_save:
|
||||
save(false,ctrlLayout);
|
||||
save(false, mControlLayout);
|
||||
break;
|
||||
}
|
||||
//Toast.makeText(MainActivity.this, menuItem.getTitle() + ":" + menuItem.getItemId(), Toast.LENGTH_SHORT).show();
|
||||
|
||||
drawerLayout.closeDrawers();
|
||||
mDrawerLayout.closeDrawers();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ctrlLayout.setActivity(this);
|
||||
ctrlLayout.setModifiable(true);
|
||||
mControlLayout.setActivity(this);
|
||||
mControlLayout.setModifiable(true);
|
||||
|
||||
loadControl(LauncherPreferences.PREF_DEFAULTCTRL_PATH,ctrlLayout);
|
||||
loadControl(LauncherPreferences.PREF_DEFAULTCTRL_PATH, mControlLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,18 +81,7 @@ public class CustomControlsActivity extends BaseActivity
|
||||
return;
|
||||
}
|
||||
|
||||
save(true,ctrlLayout);
|
||||
}
|
||||
|
||||
private static void setDefaultControlJson(String path,ControlLayout ctrlLayout) {
|
||||
try {
|
||||
// Load before save to make sure control is not error
|
||||
ctrlLayout.loadLayout(Tools.GLOBAL_GSON.fromJson(Tools.read(path), CustomControls.class));
|
||||
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultCtrl", path).commit();
|
||||
LauncherPreferences.PREF_DEFAULTCTRL_PATH = path;
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(ctrlLayout.getContext(), th);
|
||||
}
|
||||
save(true, mControlLayout);
|
||||
}
|
||||
|
||||
public static void dialogSelectDefaultCtrl(final ControlLayout layout) {
|
||||
@@ -127,18 +104,12 @@ public class CustomControlsActivity extends BaseActivity
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private static String doSaveCtrl(String name, final ControlLayout layout) throws Exception {
|
||||
String jsonPath = Tools.CTRLMAP_PATH + "/" + name + ".json";
|
||||
layout.saveLayout(jsonPath);
|
||||
|
||||
return jsonPath;
|
||||
}
|
||||
|
||||
public static void save(final boolean exit, final ControlLayout layout) {
|
||||
final Context ctx = layout.getContext();
|
||||
final EditText edit = new EditText(ctx);
|
||||
edit.setSingleLine();
|
||||
edit.setText(selectedName);
|
||||
edit.setText(sSelectedName);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||
builder.setTitle(R.string.global_save);
|
||||
@@ -162,51 +133,38 @@ public class CustomControlsActivity extends BaseActivity
|
||||
});
|
||||
}
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
dialog.setOnShowListener(dialogInterface -> {
|
||||
|
||||
@Override
|
||||
public void onShow(DialogInterface dialogInterface) {
|
||||
|
||||
Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (edit.getText().toString().isEmpty()) {
|
||||
edit.setError(ctx.getResources().getString(R.string.global_error_field_empty));
|
||||
} else {
|
||||
try {
|
||||
String jsonPath = doSaveCtrl(edit.getText().toString(),layout);
|
||||
|
||||
Toast.makeText(ctx, ctx.getString(R.string.global_save) + ": " + jsonPath, Toast.LENGTH_SHORT).show();
|
||||
|
||||
dialog.dismiss();
|
||||
if (exit) {
|
||||
if(ctx instanceof MainActivity) {
|
||||
((MainActivity) ctx).leaveCustomControls();
|
||||
}else{
|
||||
((Activity)ctx).onBackPressed();
|
||||
}
|
||||
//CustomControlsActivity.super.onBackPressed();
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(ctx, th, exit);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
button.setOnClickListener(view -> {
|
||||
if (edit.getText().toString().isEmpty()) {
|
||||
edit.setError(ctx.getResources().getString(R.string.global_error_field_empty));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String jsonPath = doSaveCtrl(edit.getText().toString(),layout);
|
||||
Toast.makeText(ctx, ctx.getString(R.string.global_save) + ": " + jsonPath, Toast.LENGTH_SHORT).show();
|
||||
|
||||
dialog.dismiss();
|
||||
if (!exit) return;
|
||||
|
||||
if(ctx instanceof MainActivity) {
|
||||
((MainActivity) ctx).leaveCustomControls();
|
||||
}else{
|
||||
((Activity)ctx).onBackPressed();
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(ctx, th, exit);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
dialog.show();
|
||||
|
||||
}
|
||||
|
||||
public static void load(final ControlLayout layout) {
|
||||
/*ControlJsonSelector sel = new ControlJsonSelector(layout.getContext(), R.string.global_load);
|
||||
sel.setFinishCallback((f)->{
|
||||
loadControl(f.getAbsolutePath(),layout);
|
||||
});
|
||||
sel.show();*/
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(layout.getContext());
|
||||
builder.setTitle(R.string.global_load);
|
||||
builder.setPositiveButton(android.R.string.cancel, null);
|
||||
@@ -227,12 +185,30 @@ public class CustomControlsActivity extends BaseActivity
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private static void setDefaultControlJson(String path,ControlLayout ctrlLayout) {
|
||||
// Load before save to make sure control is not error
|
||||
try {
|
||||
ctrlLayout.loadLayout(Tools.GLOBAL_GSON.fromJson(Tools.read(path), CustomControls.class));
|
||||
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultCtrl", path).apply();
|
||||
LauncherPreferences.PREF_DEFAULTCTRL_PATH = path;
|
||||
} catch (IOException| JsonSyntaxException exception) {
|
||||
Tools.showError(ctrlLayout.getContext(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static String doSaveCtrl(String name, final ControlLayout layout) throws Exception {
|
||||
String jsonPath = Tools.CTRLMAP_PATH + "/" + name + ".json";
|
||||
layout.saveLayout(jsonPath);
|
||||
|
||||
return jsonPath;
|
||||
}
|
||||
|
||||
private static void loadControl(String path,ControlLayout layout) {
|
||||
try {
|
||||
layout.loadLayout(path);
|
||||
selectedName = new File(path).getName();
|
||||
sSelectedName = new File(path).getName();
|
||||
// Remove `.json`
|
||||
selectedName = selectedName.substring(0, selectedName.length() - 5);
|
||||
sSelectedName = sSelectedName.substring(0, sSelectedName.length() - 5);
|
||||
} catch (Exception e) {
|
||||
Tools.showError(layout.getContext(), e);
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.content.*;
|
||||
import android.net.*;
|
||||
import androidx.browser.customtabs.*;
|
||||
|
||||
public class CustomTabs {
|
||||
|
||||
public static void openTab(Context context, String url) {
|
||||
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||
builder.setShowTitle(true);
|
||||
|
||||
CustomTabsIntent customTabsIntent = builder.build();
|
||||
customTabsIntent.launchUrl(context, Uri.parse(url));
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -16,168 +14,158 @@ public class EfficientAndroidLWJGLKeycode {
|
||||
//The key being the android keycode from a KeyEvent
|
||||
//The value its LWJGL equivalent.
|
||||
private static final int KEYCODE_COUNT = 103;
|
||||
private static final int[] androidKeycodes = new int[KEYCODE_COUNT];
|
||||
private static final short[] LWJGLKeycodes = new short[KEYCODE_COUNT];
|
||||
private static final int[] sAndroidKeycodes = new int[KEYCODE_COUNT];
|
||||
private static final short[] sLwjglKeycodes = new short[KEYCODE_COUNT];
|
||||
private static String[] androidKeyNameArray; /* = new String[androidKeycodes.length]; */
|
||||
private static int mTmpCount = 0;
|
||||
|
||||
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);
|
||||
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);
|
||||
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_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);
|
||||
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
|
||||
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_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);
|
||||
add(KeyEvent.KEYCODE_PERIOD, LWJGLGLFWKeycode.GLFW_KEY_PERIOD);
|
||||
add(KeyEvent.KEYCODE_COMMA, LwjglGlfwKeycode.GLFW_KEY_COMMA);
|
||||
add(KeyEvent.KEYCODE_PERIOD, LwjglGlfwKeycode.GLFW_KEY_PERIOD);
|
||||
|
||||
// Alt keys
|
||||
add(KeyEvent.KEYCODE_ALT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT);
|
||||
add(KeyEvent.KEYCODE_ALT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_ALT);
|
||||
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_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_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_SLASH, LwjglGlfwKeycode.GLFW_KEY_SLASH); //76
|
||||
add(KeyEvent.KEYCODE_AT, LwjglGlfwKeycode.GLFW_KEY_2);
|
||||
|
||||
add(KeyEvent.KEYCODE_PLUS, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD);
|
||||
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_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);
|
||||
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_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);
|
||||
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
|
||||
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
|
||||
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];
|
||||
androidKeyNameArray = new String[sAndroidKeycodes.length];
|
||||
for(int i=0; i < androidKeyNameArray.length; ++i){
|
||||
androidKeyNameArray[i] = KeyEvent.keyCodeToString(androidKeycodes[i]).replace("KEYCODE_", "");
|
||||
androidKeyNameArray[i] = KeyEvent.keyCodeToString(sAndroidKeycodes[i]).replace("KEYCODE_", "");
|
||||
}
|
||||
}
|
||||
return androidKeyNameArray;
|
||||
@@ -187,7 +175,6 @@ public class EfficientAndroidLWJGLKeycode {
|
||||
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();
|
||||
@@ -196,19 +183,14 @@ public class EfficientAndroidLWJGLKeycode {
|
||||
CallbackBridge.holdingNumlock = keyEvent.isNumLockOn();
|
||||
CallbackBridge.holdingShift = keyEvent.isShiftPressed();
|
||||
|
||||
try {
|
||||
System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel());
|
||||
char key = (char)(keyEvent.getUnicodeChar() != 0 ? keyEvent.getUnicodeChar() : '\u0000');
|
||||
sendKeyPress(
|
||||
getValueByIndex(valueIndex),
|
||||
key,
|
||||
0,
|
||||
CallbackBridge.getCurrentMods(),
|
||||
keyEvent.getAction() == KeyEvent.ACTION_DOWN);
|
||||
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel());
|
||||
char key = (char)(keyEvent.getUnicodeChar() != 0 ? keyEvent.getUnicodeChar() : '\u0000');
|
||||
sendKeyPress(
|
||||
getValueByIndex(valueIndex),
|
||||
key,
|
||||
0,
|
||||
CallbackBridge.getCurrentMods(),
|
||||
keyEvent.getAction() == KeyEvent.ACTION_DOWN);
|
||||
}
|
||||
|
||||
public static void execKeyIndex(int index){
|
||||
@@ -217,24 +199,29 @@ public class EfficientAndroidLWJGLKeycode {
|
||||
}
|
||||
|
||||
public static int getValueByIndex(int index) {
|
||||
return LWJGLKeycodes[index];
|
||||
return sLwjglKeycodes[index];
|
||||
}
|
||||
|
||||
public static int getIndexByKey(int key){
|
||||
return Arrays.binarySearch(androidKeycodes, key);
|
||||
return Arrays.binarySearch(sAndroidKeycodes, key);
|
||||
}
|
||||
|
||||
public static short getValue(int key){
|
||||
return LWJGLKeycodes[Arrays.binarySearch(androidKeycodes, key)];
|
||||
return sLwjglKeycodes[Arrays.binarySearch(sAndroidKeycodes, key)];
|
||||
}
|
||||
|
||||
/** @return the index at which the key is in the array, searching linearly */
|
||||
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;
|
||||
for (int i = 0; i < sLwjglKeycodes.length; i++) {
|
||||
if(sLwjglKeycodes[i] == lwjglKey) return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void add(int androidKeycode, short LWJGLKeycode){
|
||||
sAndroidKeycodes[mTmpCount] = androidKeycode;
|
||||
sLwjglKeycodes[mTmpCount] = LWJGLKeycode;
|
||||
mTmpCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
@@ -11,13 +12,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
@Keep
|
||||
public class ExitActivity extends AppCompatActivity {
|
||||
public static void showExitMessage(Context ctx, int code) {
|
||||
Intent i = new Intent(ctx,ExitActivity.class);
|
||||
i.putExtra("code",code);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ctx.startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -26,14 +21,20 @@ public class ExitActivity extends AppCompatActivity {
|
||||
if(extras != null) {
|
||||
code = extras.getInt("code",-1);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(getString(R.string.mcn_exit_title,code))
|
||||
.setPositiveButton(android.R.string.ok,(dialog,which)->{
|
||||
dialog.dismiss();
|
||||
ExitActivity.this.finish();
|
||||
}).setOnCancelListener((z)->{
|
||||
ExitActivity.this.finish();
|
||||
})
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setOnDismissListener(dialog -> ExitActivity.this.finish())
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void showExitMessage(Context ctx, int code) {
|
||||
Intent i = new Intent(ctx,ExitActivity.class);
|
||||
i.putExtra("code",code);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ctx.startActivity(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +1,47 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import androidx.appcompat.app.*;
|
||||
import android.util.*;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FatalErrorActivity extends AppCompatActivity
|
||||
{
|
||||
public static void showError(Context ctx, String savePath, boolean storageAllow, /* boolean isFatalErr, */ Throwable th) {
|
||||
Intent ferrorIntent = new Intent(ctx, FatalErrorActivity.class);
|
||||
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ferrorIntent.putExtra("throwable", th);
|
||||
ferrorIntent.putExtra("savePath", savePath);
|
||||
ferrorIntent.putExtra("storageAllow", storageAllow);
|
||||
// ferrorIntent.putExtra("isFatal", isFatalErr);
|
||||
ctx.startActivity(ferrorIntent);
|
||||
}
|
||||
|
||||
public class FatalErrorActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
boolean storageAllow = extras.getBoolean("storageAllow");
|
||||
final String strStackTrace = Log.getStackTraceString((Throwable) extras.getSerializable("throwable"));
|
||||
final String stackTrace = Log.getStackTraceString((Throwable) extras.getSerializable("throwable"));
|
||||
String strSavePath = extras.getString("savePath");
|
||||
String errHeader = storageAllow ?
|
||||
"Crash stack trace saved to " + strSavePath + "." :
|
||||
"Storage permission is required to save crash stack trace!";
|
||||
|
||||
// boolean isFatalError = extras.getBoolean("isFatal", false);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.error_fatal)
|
||||
.setMessage(errHeader + "\n\n" + strStackTrace)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
.setMessage(errHeader + "\n\n" + stackTrace)
|
||||
.setPositiveButton(android.R.string.ok, (p1, p2) -> finish())
|
||||
.setNegativeButton(R.string.global_restart, (p1, p2) -> startActivity(new Intent(FatalErrorActivity.this, PojavLoginActivity.class)))
|
||||
.setNeutralButton(android.R.string.copy, (p1, p2) -> {
|
||||
ClipboardManager mgr = (ClipboardManager) FatalErrorActivity.this.getSystemService(CLIPBOARD_SERVICE);
|
||||
mgr.setPrimaryClip(ClipData.newPlainText("error", stackTrace));
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2) {
|
||||
finish();
|
||||
}
|
||||
finish();
|
||||
})
|
||||
.setNegativeButton(R.string.global_restart, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2) {
|
||||
startActivity(new Intent(FatalErrorActivity.this, PojavLoginActivity.class));
|
||||
}
|
||||
})
|
||||
.setNeutralButton(android.R.string.copy, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2) {
|
||||
ClipboardManager mgr = (ClipboardManager) FatalErrorActivity.this.getSystemService(CLIPBOARD_SERVICE);
|
||||
mgr.setPrimaryClip(ClipData.newPlainText("error", strStackTrace));
|
||||
|
||||
finish();
|
||||
}
|
||||
})
|
||||
//.setNegativeButton("Report (not available)", null)
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
|
||||
// Tools.showError(this, isFatalError ? R.string.error_fatal : R.string.global_error, th, true);
|
||||
}
|
||||
|
||||
public static void showError(Context ctx, String savePath, boolean storageAllow, Throwable th) {
|
||||
Intent ferrorIntent = new Intent(ctx, FatalErrorActivity.class);
|
||||
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ferrorIntent.putExtra("throwable", th);
|
||||
ferrorIntent.putExtra("savePath", savePath);
|
||||
ferrorIntent.putExtra("storageAllow", storageAllow);
|
||||
ctx.startActivity(ferrorIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ImportControlActivity extends Activity {
|
||||
super.onCreate(savedInstanceState);
|
||||
Tools.initContextConstants(getApplicationContext());
|
||||
|
||||
setContentView(R.layout.import_control_layout);
|
||||
setContentView(R.layout.activity_import_control);
|
||||
mEditText = findViewById(R.id.editText_import_control_file_name);
|
||||
}
|
||||
|
||||
@@ -185,12 +185,10 @@ public class ImportControlActivity extends Activity {
|
||||
String jsonLayoutData = Tools.read(Tools.CTRLMAP_PATH + "/TMP_IMPORT_FILE.json");
|
||||
JSONObject layoutJobj = new JSONObject(jsonLayoutData);
|
||||
return layoutJobj.has("version") && layoutJobj.has("mControlDataList");
|
||||
|
||||
}catch (JSONException | IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getNameFromURI(Uri uri) {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import android.os.*;
|
||||
|
||||
public class InstallerTask extends AsyncTask<String, Void, String>
|
||||
{
|
||||
@Override
|
||||
protected String doInBackground(String[] p1)
|
||||
{
|
||||
try
|
||||
{
|
||||
downloadLibraries(p1[0]);
|
||||
dexMinecraftLibs();
|
||||
downloadMinecraft(p1[0]);
|
||||
dexMinecraftClient(p1[0]);
|
||||
downloadAssets(p1[0]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(String result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
|
||||
if(result == null){
|
||||
//No errors
|
||||
}
|
||||
}
|
||||
private void downloadLibraries(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void dexMinecraftLibs() throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void downloadMinecraft(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void dexMinecraftClient(String version) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void downloadAssets(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class JAssets {
|
||||
public boolean map_to_resources;
|
||||
@SerializedName("map_to_resources") public boolean mapToResources;
|
||||
public Map<String, JAssetInfo> objects;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.view.View.*;
|
||||
import android.widget.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -23,169 +22,121 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
private static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
|
||||
|
||||
private AWTCanvasView mTextureView;
|
||||
private LoggerView loggerView;
|
||||
private LoggerView mLoggerView;
|
||||
|
||||
private LinearLayout touchPad;
|
||||
private ImageView mousePointer;
|
||||
private LinearLayout mTouchPad;
|
||||
private ImageView mMousePointerImageView;
|
||||
private GestureDetector gestureDetector;
|
||||
|
||||
private boolean mSkipDetectMod, mIsVirtualMouseEnabled;
|
||||
|
||||
private int mScaleFactor;
|
||||
private int[] mScaleFactors = initScaleFactors();
|
||||
|
||||
private final Object mDialogLock = new Object();
|
||||
|
||||
private boolean mSkipDetectMod, isVirtualMouseEnabled;
|
||||
|
||||
private int scaleFactor;
|
||||
private int[] scaleFactors = initScaleFactors();
|
||||
|
||||
private final int fingerStillThreshold = 8;
|
||||
private int initialX;
|
||||
private int initialY;
|
||||
private static boolean triggeredLeftMouseButton = false;
|
||||
private Handler theHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_LEFT_MOUSE_BUTTON_CHECK: {
|
||||
float x = CallbackBridge.mouseX;
|
||||
float y = CallbackBridge.mouseY;
|
||||
if (CallbackBridge.isGrabbing() &&
|
||||
Math.abs(initialX - x) < fingerStillThreshold &&
|
||||
Math.abs(initialY - y) < fingerStillThreshold) {
|
||||
triggeredLeftMouseButton = true;
|
||||
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK, true);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.install_mod);
|
||||
setContentView(R.layout.activity_java_gui_launcher);
|
||||
|
||||
Tools.updateWindowSize(this);
|
||||
Logger.getInstance().reset();
|
||||
|
||||
|
||||
mTouchPad = findViewById(R.id.main_touchpad);
|
||||
mLoggerView = findViewById(R.id.launcherLoggerView);
|
||||
mMousePointerImageView = findViewById(R.id.main_mouse_pointer);
|
||||
mTextureView = findViewById(R.id.installmod_surfaceview);
|
||||
gestureDetector = new GestureDetector(this, new SingleTapConfirm());
|
||||
mTouchPad.setFocusable(false);
|
||||
mTouchPad.setVisibility(View.GONE);
|
||||
|
||||
findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this);
|
||||
findViewById(R.id.installmod_mouse_sec).setOnTouchListener(this);
|
||||
|
||||
mMousePointerImageView.post(() -> {
|
||||
ViewGroup.LayoutParams params = mMousePointerImageView.getLayoutParams();
|
||||
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
});
|
||||
|
||||
mTouchPad.setOnTouchListener((v, event) -> {
|
||||
// MotionEvent reports input details from the touch screen
|
||||
// and other input controls. In this case, you are only
|
||||
// interested in events where the touch position changed.
|
||||
// int index = event.getActionIndex();
|
||||
int action = event.getActionMasked();
|
||||
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
float prevX, prevY, mouseX, mouseY;
|
||||
if(event.getHistorySize() > 0) {
|
||||
prevX = event.getHistoricalX(0);
|
||||
prevY = event.getHistoricalY(0);
|
||||
}else{
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
}
|
||||
|
||||
mouseX = mMousePointerImageView.getX();
|
||||
mouseY = mMousePointerImageView.getY();
|
||||
|
||||
if (gestureDetector.onTouchEvent(event)) {
|
||||
sendScaledMousePosition(mouseX,mouseY);
|
||||
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
|
||||
} else {
|
||||
if (action == MotionEvent.ACTION_MOVE) { // 2
|
||||
mouseX = Math.max(0, Math.min(CallbackBridge.physicalWidth, mouseX + x - prevX));
|
||||
mouseY = Math.max(0, Math.min(CallbackBridge.physicalHeight, mouseY + y - prevY));
|
||||
placeMouseAt(mouseX, mouseY);
|
||||
sendScaledMousePosition(mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
// debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
return true;
|
||||
});
|
||||
|
||||
mTextureView.setOnTouchListener((v, event) -> {
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
if (gestureDetector.onTouchEvent(event)) {
|
||||
sendScaledMousePosition(x, y);
|
||||
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
sendScaledMousePosition(x, y);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
try {
|
||||
JREUtils.jreReleaseList = JREUtils.readJREReleaseProperties(LauncherPreferences.PREF_DEFAULT_RUNTIME);
|
||||
if (JREUtils.jreReleaseList.get("JAVA_VERSION").equals("1.8.0")) {
|
||||
MultiRTUtils.setRuntimeNamed(this,LauncherPreferences.PREF_DEFAULT_RUNTIME);
|
||||
} else {
|
||||
MultiRTUtils.setRuntimeNamed(this,MultiRTUtils.getExactJREName(8));
|
||||
MultiRTUtils.setRuntimeNamed(this,MultiRTUtils.getExactJreName(8));
|
||||
JREUtils.jreReleaseList = JREUtils.readJREReleaseProperties();
|
||||
}
|
||||
|
||||
loggerView = findViewById(R.id.launcherLoggerView);
|
||||
gestureDetector = new GestureDetector(this, new SingleTapConfirm());
|
||||
|
||||
findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this);
|
||||
findViewById(R.id.installmod_mouse_sec).setOnTouchListener(this);
|
||||
|
||||
this.touchPad = findViewById(R.id.main_touchpad);
|
||||
touchPad.setFocusable(false);
|
||||
touchPad.setVisibility(View.GONE);
|
||||
|
||||
this.mousePointer = findViewById(R.id.main_mouse_pointer);
|
||||
this.mousePointer.post(() -> {
|
||||
ViewGroup.LayoutParams params = mousePointer.getLayoutParams();
|
||||
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
});
|
||||
|
||||
touchPad.setOnTouchListener(new OnTouchListener(){
|
||||
private float prevX, prevY;
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
// MotionEvent reports input details from the touch screen
|
||||
// and other input controls. In this case, you are only
|
||||
// interested in events where the touch position changed.
|
||||
// int index = event.getActionIndex();
|
||||
|
||||
int action = event.getActionMasked();
|
||||
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
if(event.getHistorySize() > 0) {
|
||||
prevX = event.getHistoricalX(0);
|
||||
prevY = event.getHistoricalY(0);
|
||||
}else{
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
}
|
||||
float mouseX = mousePointer.getX();
|
||||
float mouseY = mousePointer.getY();
|
||||
|
||||
if (gestureDetector.onTouchEvent(event)) {
|
||||
|
||||
sendScaledMousePosition(mouseX,mouseY);
|
||||
|
||||
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
|
||||
} else {
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
mouseX = Math.max(0, Math.min(CallbackBridge.physicalWidth, mouseX + x - prevX));
|
||||
mouseY = Math.max(0, Math.min(CallbackBridge.physicalHeight, mouseY + y - prevY));
|
||||
placeMouseAt(mouseX, mouseY);
|
||||
|
||||
sendScaledMousePosition(mouseX,mouseY);
|
||||
/*
|
||||
if (!CallbackBridge.isGrabbing()) {
|
||||
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, 0, isLeftMouseDown);
|
||||
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, 0, isRightMouseDown);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
placeMouseAt(CallbackBridge.physicalWidth / 2, CallbackBridge.physicalHeight / 2);
|
||||
|
||||
// this.textLogBehindGL = (TextView) findViewById(R.id.main_log_behind_GL);
|
||||
// this.textLogBehindGL.setTypeface(Typeface.MONOSPACE);
|
||||
|
||||
final File modFile = (File) getIntent().getExtras().getSerializable("modFile");
|
||||
final String javaArgs = getIntent().getExtras().getString("javaArgs");
|
||||
|
||||
mTextureView = findViewById(R.id.installmod_surfaceview);
|
||||
mTextureView.setOnTouchListener((v, event) -> {
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
if (gestureDetector.onTouchEvent(event)) {
|
||||
sendScaledMousePosition(x, y);
|
||||
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
sendScaledMousePosition(x, y);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
mSkipDetectMod = getIntent().getExtras().getBoolean("skipDetectMod", false);
|
||||
if (mSkipDetectMod) {
|
||||
new Thread(() -> launchJavaRuntime(modFile, javaArgs), "JREMainThread").start();
|
||||
return;
|
||||
}
|
||||
|
||||
// No skip detection
|
||||
openLogOutput(null);
|
||||
new Thread(() -> {
|
||||
@@ -209,6 +160,14 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
final View decorView = getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent e) {
|
||||
boolean isDown;
|
||||
@@ -239,18 +198,18 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
}
|
||||
|
||||
public void placeMouseAdd(float x, float y) {
|
||||
this.mousePointer.setX(mousePointer.getX() + x);
|
||||
this.mousePointer.setY(mousePointer.getY() + y);
|
||||
mMousePointerImageView.setX(mMousePointerImageView.getX() + x);
|
||||
mMousePointerImageView.setY(mMousePointerImageView.getY() + y);
|
||||
}
|
||||
|
||||
public void placeMouseAt(float x, float y) {
|
||||
this.mousePointer.setX(x);
|
||||
this.mousePointer.setY(y);
|
||||
mMousePointerImageView.setX(x);
|
||||
mMousePointerImageView.setY(y);
|
||||
}
|
||||
|
||||
void sendScaledMousePosition(float x, float y){
|
||||
AWTInputBridge.sendMousePos((int) map(x,0,CallbackBridge.physicalWidth, scaleFactors[0], scaleFactors[2]),
|
||||
(int) map(y,0,CallbackBridge.physicalHeight, scaleFactors[1], scaleFactors[3]));
|
||||
AWTInputBridge.sendMousePos((int) map(x,0,CallbackBridge.physicalWidth, mScaleFactors[0], mScaleFactors[2]),
|
||||
(int) map(y,0,CallbackBridge.physicalHeight, mScaleFactors[1], mScaleFactors[3]));
|
||||
}
|
||||
|
||||
public void forceClose(View v) {
|
||||
@@ -258,32 +217,27 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
}
|
||||
|
||||
public void openLogOutput(View v) {
|
||||
loggerView.setVisibility(View.VISIBLE);
|
||||
mLoggerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void closeLogOutput(View view) {
|
||||
if (mSkipDetectMod) {
|
||||
loggerView.setVisibility(View.GONE);
|
||||
mLoggerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
forceClose(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleVirtualMouse(View v) {
|
||||
isVirtualMouseEnabled = !isVirtualMouseEnabled;
|
||||
touchPad.setVisibility(isVirtualMouseEnabled ? View.VISIBLE : View.GONE);
|
||||
mIsVirtualMouseEnabled = !mIsVirtualMouseEnabled;
|
||||
mTouchPad.setVisibility(mIsVirtualMouseEnabled ? View.VISIBLE : View.GONE);
|
||||
Toast.makeText(this,
|
||||
isVirtualMouseEnabled ? R.string.control_mouseon : R.string.control_mouseoff,
|
||||
mIsVirtualMouseEnabled ? R.string.control_mouseon : R.string.control_mouseoff,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private int doCustomInstall(File modFile, String javaArgs) throws IOException {
|
||||
mSkipDetectMod = true;
|
||||
return launchJavaRuntime(modFile, javaArgs);
|
||||
}
|
||||
|
||||
public int launchJavaRuntime(File modFile, String javaArgs) {
|
||||
JREUtils.redirectAndPrintJRELog(this);
|
||||
JREUtils.redirectAndPrintJRELog();
|
||||
try {
|
||||
List<String> javaArgList = new ArrayList<String>();
|
||||
|
||||
@@ -313,13 +267,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
final View decorView = getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
|
||||
|
||||
int[] initScaleFactors(){
|
||||
return initScaleFactors(true);
|
||||
@@ -330,37 +278,42 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
|
||||
if(autoScale) { //Auto scale
|
||||
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
|
||||
scaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
|
||||
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
|
||||
}
|
||||
|
||||
int[] scales = new int[4]; //Left, Top, Right, Bottom
|
||||
|
||||
scales[0] = (CallbackBridge.physicalWidth/2);
|
||||
scales[0] -= scales[0]/scaleFactor;
|
||||
scales[0] -= scales[0]/ mScaleFactor;
|
||||
|
||||
scales[1] = (CallbackBridge.physicalHeight/2);
|
||||
scales[1] -= scales[1]/scaleFactor;
|
||||
scales[1] -= scales[1]/ mScaleFactor;
|
||||
|
||||
scales[2] = (CallbackBridge.physicalWidth/2);
|
||||
scales[2] += scales[2]/scaleFactor;
|
||||
scales[2] += scales[2]/ mScaleFactor;
|
||||
|
||||
scales[3] = (CallbackBridge.physicalHeight/2);
|
||||
scales[3] += scales[3]/scaleFactor;
|
||||
scales[3] += scales[3]/ mScaleFactor;
|
||||
|
||||
return scales;
|
||||
}
|
||||
|
||||
public void scaleDown(View view) {
|
||||
scaleFactor = Math.max(scaleFactor - 1, 1);
|
||||
scaleFactors = initScaleFactors(false);
|
||||
mTextureView.initScaleFactors(scaleFactor);
|
||||
sendScaledMousePosition(mousePointer.getX(),mousePointer.getY());
|
||||
mScaleFactor = Math.max(mScaleFactor - 1, 1);
|
||||
mScaleFactors = initScaleFactors(false);
|
||||
mTextureView.initScaleFactors(mScaleFactor);
|
||||
sendScaledMousePosition(mMousePointerImageView.getX(), mMousePointerImageView.getY());
|
||||
}
|
||||
|
||||
public void scaleUp(View view) {
|
||||
scaleFactor = Math.min(scaleFactor + 1, 6);
|
||||
scaleFactors = initScaleFactors(false);
|
||||
mTextureView.initScaleFactors(scaleFactor);
|
||||
sendScaledMousePosition(mousePointer.getX(),mousePointer.getY());
|
||||
mScaleFactor = Math.min(mScaleFactor + 1, 6);
|
||||
mScaleFactors = initScaleFactors(false);
|
||||
mTextureView.initScaleFactors(mScaleFactor);
|
||||
sendScaledMousePosition(mMousePointerImageView.getX(), mMousePointerImageView.getY());
|
||||
}
|
||||
|
||||
private int doCustomInstall(File modFile, String javaArgs) throws IOException {
|
||||
mSkipDetectMod = true;
|
||||
return launchJavaRuntime(modFile, javaArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ import java.lang.ref.WeakReference;
|
||||
*/
|
||||
@Keep
|
||||
public class Logger {
|
||||
private static Logger loggerSingleton = null;
|
||||
private static Logger sLoggerSingleton = null;
|
||||
|
||||
/* Instance variables */
|
||||
private final File logFile;
|
||||
private PrintStream logStream;
|
||||
private WeakReference<eventLogListener> logListenerWeakReference = null;
|
||||
private final File mLogFile;
|
||||
private PrintStream mLogStream;
|
||||
private WeakReference<eventLogListener> mLogListenerWeakReference = null;
|
||||
|
||||
/* No public construction */
|
||||
private Logger(){
|
||||
@@ -25,25 +25,25 @@ public class Logger {
|
||||
}
|
||||
|
||||
private Logger(String fileName){
|
||||
logFile = new File(Tools.DIR_GAME_HOME, fileName);
|
||||
mLogFile = new File(Tools.DIR_GAME_HOME, fileName);
|
||||
// Make a new instance of the log file
|
||||
logFile.delete();
|
||||
mLogFile.delete();
|
||||
try {
|
||||
logFile.createNewFile();
|
||||
logStream = new PrintStream(logFile.getAbsolutePath());
|
||||
mLogFile.createNewFile();
|
||||
mLogStream = new PrintStream(mLogFile.getAbsolutePath());
|
||||
}catch (IOException e){e.printStackTrace();}
|
||||
|
||||
}
|
||||
|
||||
public static Logger getInstance(){
|
||||
if(loggerSingleton == null){
|
||||
if(sLoggerSingleton == null){
|
||||
synchronized(Logger.class){
|
||||
if(loggerSingleton == null){
|
||||
loggerSingleton = new Logger();
|
||||
if(sLoggerSingleton == null){
|
||||
sLoggerSingleton = new Logger();
|
||||
}
|
||||
}
|
||||
}
|
||||
return loggerSingleton;
|
||||
return sLoggerSingleton;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,22 +55,22 @@ public class Logger {
|
||||
|
||||
/** Print the text to the log file, no china censoring there */
|
||||
public void appendToLogUnchecked(String text){
|
||||
logStream.println(text);
|
||||
mLogStream.println(text);
|
||||
notifyLogListener(text);
|
||||
}
|
||||
|
||||
/** Reset the log file, effectively erasing any previous logs */
|
||||
public void reset(){
|
||||
try{
|
||||
logFile.delete();
|
||||
logFile.createNewFile();
|
||||
logStream = new PrintStream(logFile.getAbsolutePath());
|
||||
mLogFile.delete();
|
||||
mLogFile.createNewFile();
|
||||
mLogStream = new PrintStream(mLogFile.getAbsolutePath());
|
||||
}catch (IOException e){ e.printStackTrace();}
|
||||
}
|
||||
|
||||
/** Disables the printing */
|
||||
public void shutdown(){
|
||||
logStream.close();
|
||||
mLogStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,15 +91,15 @@ public class Logger {
|
||||
|
||||
/** Link a log listener to the logger */
|
||||
public void setLogListener(eventLogListener logListener){
|
||||
this.logListenerWeakReference = new WeakReference<>(logListener);
|
||||
this.mLogListenerWeakReference = new WeakReference<>(logListener);
|
||||
}
|
||||
|
||||
/** Notifies the event listener, if it exists */
|
||||
private void notifyLogListener(String text){
|
||||
if(logListenerWeakReference == null) return;
|
||||
eventLogListener logListener = logListenerWeakReference.get();
|
||||
if(mLogListenerWeakReference == null) return;
|
||||
eventLogListener logListener = mLogListenerWeakReference.get();
|
||||
if(logListener == null){
|
||||
logListenerWeakReference = null;
|
||||
mLogListenerWeakReference = null;
|
||||
return;
|
||||
}
|
||||
logListener.onEventLogged(text);
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class LWJGLGLFWKeycode
|
||||
{
|
||||
public class LwjglGlfwKeycode {
|
||||
/** The unknown key. */
|
||||
public static final short GLFW_KEY_UNKNOWN = 0; // should be -1
|
||||
|
||||
@@ -195,5 +194,8 @@ public class LWJGLGLFWKeycode
|
||||
GLFW_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1,
|
||||
GLFW_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2,
|
||||
GLFW_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3;
|
||||
|
||||
|
||||
public static final int
|
||||
GLFW_VISIBLE = 0x20004,
|
||||
GLFW_HOVERED = 0x2000B;
|
||||
}
|
||||
@@ -5,8 +5,6 @@ import android.content.Intent;
|
||||
import android.os.*;
|
||||
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.*;
|
||||
import net.kdt.pojavlaunch.prefs.*;
|
||||
import net.kdt.pojavlaunch.utils.MCOptionUtils;
|
||||
@@ -15,7 +13,6 @@ import java.io.*;
|
||||
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_SUSTAINED_PERFORMANCE;
|
||||
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
||||
|
||||
public class MainActivity extends BaseMainActivity {
|
||||
public static ControlLayout mControlLayout;
|
||||
@@ -25,7 +22,7 @@ public class MainActivity extends BaseMainActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initLayout(R.layout.main_with_customctrl);
|
||||
initLayout(R.layout.activity_basemain);
|
||||
|
||||
// Set the sustained performance mode for available APIs
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
|
||||
@@ -11,20 +11,17 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
|
||||
import android.app.Activity;
|
||||
import android.content.*;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.google.android.material.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.TouchCharInput;
|
||||
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
|
||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
import net.kdt.pojavlaunch.utils.JREUtils;
|
||||
@@ -36,44 +33,6 @@ import org.lwjgl.glfw.CallbackBridge;
|
||||
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
|
||||
*/
|
||||
public class MinecraftGLView extends TextureView {
|
||||
/* Gamepad object for gamepad inputs, instantiated on need */
|
||||
private Gamepad gamepad = null;
|
||||
/* Pointer Debug textview, used to show info about the pointer state */
|
||||
private TextView pointerDebugText;
|
||||
/* Resolution scaler option, allow downsizing a window */
|
||||
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
/* Display properties, such as resolution and DPI */
|
||||
private final DisplayMetrics displayMetrics = Tools.getDisplayMetrics((Activity) getContext());
|
||||
/* Sensitivity, adjusted according to screen size */
|
||||
private final double sensitivityFactor = (1.4 * (1080f/ displayMetrics.heightPixels));
|
||||
/* Use to detect simple and double taps */
|
||||
private final TapDetector singleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
|
||||
private final TapDetector doubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
|
||||
/* MC GUI scale, listened by MCOptionUtils */
|
||||
private int GUIScale = getMcScale();
|
||||
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> GUIScale = getMcScale();
|
||||
/* Surface ready listener, used by the activity to launch minecraft */
|
||||
SurfaceReadyListener surfaceReadyListener = null;
|
||||
|
||||
/* List of hotbarKeys, used when clicking on the hotbar */
|
||||
private static final int[] hotbarKeys = {
|
||||
LWJGLGLFWKeycode.GLFW_KEY_1, LWJGLGLFWKeycode.GLFW_KEY_2, LWJGLGLFWKeycode.GLFW_KEY_3,
|
||||
LWJGLGLFWKeycode.GLFW_KEY_4, LWJGLGLFWKeycode.GLFW_KEY_5, LWJGLGLFWKeycode.GLFW_KEY_6,
|
||||
LWJGLGLFWKeycode.GLFW_KEY_7, LWJGLGLFWKeycode.GLFW_KEY_8, LWJGLGLFWKeycode.GLFW_KEY_9};
|
||||
/* Last hotbar button (0-9) registered */
|
||||
private int lastHotbarKey = -1;
|
||||
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
|
||||
private boolean shouldBeDown = false;
|
||||
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
|
||||
private int lastPointerCount = 0;
|
||||
/* Previous MotionEvent position, not scale */
|
||||
private float prevX, prevY;
|
||||
/* PointerID used for the moving camera */
|
||||
private int currentPointerID = -1000;
|
||||
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
|
||||
private float initialX, initialY;
|
||||
/* Last first pointer positions non-scaled, used to scroll distance */
|
||||
private float scrollLastInitialX, scrollLastInitialY;
|
||||
/* How much distance a finger has to go for touch sloppiness to be disabled */
|
||||
public static final int FINGER_STILL_THRESHOLD = (int) Tools.dpToPx(9);
|
||||
/* How much distance a finger has to go to scroll */
|
||||
@@ -81,6 +40,46 @@ public class MinecraftGLView extends TextureView {
|
||||
/* Handle hotbar throw button and mouse mining button */
|
||||
public static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
|
||||
public static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029;
|
||||
|
||||
/* Gamepad object for gamepad inputs, instantiated on need */
|
||||
private Gamepad mGamepad = null;
|
||||
/* Pointer Debug textview, used to show info about the pointer state */
|
||||
private TextView mPointerDebugTextView;
|
||||
/* Resolution scaler option, allow downsizing a window */
|
||||
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
/* Display properties, such as resolution and DPI */
|
||||
private final DisplayMetrics mDisplayMetrics = Tools.getDisplayMetrics((Activity) getContext());
|
||||
/* Sensitivity, adjusted according to screen size */
|
||||
private final double mSensitivityFactor = (1.4 * (1080f/ mDisplayMetrics.heightPixels));
|
||||
/* Use to detect simple and double taps */
|
||||
private final TapDetector mSingleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
|
||||
private final TapDetector mDoubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
|
||||
/* MC GUI scale, listened by MCOptionUtils */
|
||||
private int mGuiScale = getMcScale();
|
||||
private MCOptionUtils.MCOptionListener mGuiScaleListener = () -> mGuiScale = getMcScale();
|
||||
/* Surface ready listener, used by the activity to launch minecraft */
|
||||
SurfaceReadyListener mSurfaceReadyListener = null;
|
||||
|
||||
/* List of hotbarKeys, used when clicking on the hotbar */
|
||||
private static final int[] sHotbarKeys = {
|
||||
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
|
||||
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
|
||||
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
|
||||
/* Last hotbar button (0-9) registered */
|
||||
private int mLastHotbarKey = -1;
|
||||
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
|
||||
private boolean mShouldBeDown = false;
|
||||
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
|
||||
private int mLastPointerCount = 0;
|
||||
/* Previous MotionEvent position, not scale */
|
||||
private float mPrevX, mPrevY;
|
||||
/* PointerID used for the moving camera */
|
||||
private int mCurrentPointerID = -1000;
|
||||
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
|
||||
private float mInitialX, mInitialY;
|
||||
/* Last first pointer positions non-scaled, used to scroll distance */
|
||||
private float mScrollLastInitialX, mScrollLastInitialY;
|
||||
/* Handle hotbar throw button and mouse mining button */
|
||||
private final Handler theHandler = new Handler(Looper.getMainLooper()) {
|
||||
public void handleMessage(Message msg) {
|
||||
if(msg.what == MSG_LEFT_MOUSE_BUTTON_CHECK) {
|
||||
@@ -88,15 +87,15 @@ public class MinecraftGLView extends TextureView {
|
||||
float x = CallbackBridge.mouseX;
|
||||
float y = CallbackBridge.mouseY;
|
||||
if (CallbackBridge.isGrabbing() &&
|
||||
MathUtils.dist(x, y, initialX, initialY) < FINGER_STILL_THRESHOLD) {
|
||||
triggeredLeftMouseButton = true;
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
|
||||
MathUtils.dist(x, y, mInitialX, mInitialY) < FINGER_STILL_THRESHOLD) {
|
||||
mTriggeredLeftMouseButton = true;
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(msg.what == MSG_DROP_ITEM_BUTTON_CHECK) {
|
||||
if(CallbackBridge.isGrabbing()){
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q);
|
||||
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 600);
|
||||
}
|
||||
return;
|
||||
@@ -105,7 +104,9 @@ public class MinecraftGLView extends TextureView {
|
||||
}
|
||||
};
|
||||
/* Whether the button was triggered, used by the handler */
|
||||
private static boolean triggeredLeftMouseButton = false;
|
||||
private boolean mTriggeredLeftMouseButton = false;
|
||||
/* Whether the pointer debug has failed at some point */
|
||||
private boolean debugErrored = false;
|
||||
|
||||
|
||||
public MinecraftGLView(Context context) {
|
||||
@@ -119,68 +120,7 @@ public class MinecraftGLView extends TextureView {
|
||||
setOpaque(false);
|
||||
setFocusable(true);
|
||||
|
||||
MCOptionUtils.addMCOptionListener(GUIScaleListener);
|
||||
}
|
||||
|
||||
/** Initialize the view and all its settings */
|
||||
public void start(){
|
||||
// Add the pointer debug textview
|
||||
pointerDebugText = new TextView(getContext());
|
||||
pointerDebugText.setX(0);
|
||||
pointerDebugText.setY(0);
|
||||
pointerDebugText.setVisibility(GONE);
|
||||
((ViewGroup)getParent()).addView(pointerDebugText);
|
||||
|
||||
setSurfaceTextureListener(new SurfaceTextureListener() {
|
||||
private boolean isCalled = false;
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
|
||||
windowWidth = Tools.getDisplayFriendlyRes(width, scaleFactor);
|
||||
windowHeight = Tools.getDisplayFriendlyRes(height, scaleFactor);
|
||||
texture.setDefaultBufferSize(windowWidth, windowHeight);
|
||||
|
||||
//Load Minecraft options:
|
||||
MCOptionUtils.load();
|
||||
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
|
||||
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
|
||||
MCOptionUtils.save();
|
||||
getMcScale();
|
||||
// Should we do that?
|
||||
if(isCalled) return;
|
||||
isCalled = true;
|
||||
|
||||
JREUtils.setupBridgeWindow(new Surface(texture));
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
if(surfaceReadyListener != null){
|
||||
surfaceReadyListener.isReady();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Tools.showError(getContext(), e, true);
|
||||
}
|
||||
}, "JVM Main thread").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
|
||||
windowWidth = Tools.getDisplayFriendlyRes(width, scaleFactor);
|
||||
windowHeight = Tools.getDisplayFriendlyRes(height, scaleFactor);
|
||||
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
|
||||
getMcScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
||||
texture.setDefaultBufferSize(windowWidth, windowHeight);
|
||||
}
|
||||
});
|
||||
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +136,7 @@ public class MinecraftGLView extends TextureView {
|
||||
|
||||
// Mouse found
|
||||
if(CallbackBridge.isGrabbing()) return false;
|
||||
CallbackBridge.sendCursorPos( e.getX(i) * scaleFactor, e.getY(i) * scaleFactor);
|
||||
CallbackBridge.sendCursorPos( e.getX(i) * mScaleFactor, e.getY(i) * mScaleFactor);
|
||||
return true; //mouse event handled successfully
|
||||
}
|
||||
|
||||
@@ -205,17 +145,17 @@ public class MinecraftGLView extends TextureView {
|
||||
//Getting scaled position from the event
|
||||
/* Tells if a double tap happened [MOUSE GRAB ONLY]. Doesn't tell where though. */
|
||||
if(!CallbackBridge.isGrabbing()) {
|
||||
CallbackBridge.mouseX = (e.getX() * scaleFactor);
|
||||
CallbackBridge.mouseY = (e.getY() * scaleFactor);
|
||||
CallbackBridge.mouseX = (e.getX() * mScaleFactor);
|
||||
CallbackBridge.mouseY = (e.getY() * mScaleFactor);
|
||||
//One android click = one MC click
|
||||
if(singleTapDetector.onTouchEvent(e)){
|
||||
CallbackBridge.putMouseEventWithCoords(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
if(mSingleTapDetector.onTouchEvent(e)){
|
||||
CallbackBridge.putMouseEventWithCoords(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check double tap state, used for the hotbar
|
||||
boolean hasDoubleTapped = doubleTapDetector.onTouchEvent(e);
|
||||
boolean hasDoubleTapped = mDoubleTapDetector.onTouchEvent(e);
|
||||
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
@@ -227,46 +167,46 @@ public class MinecraftGLView extends TextureView {
|
||||
// Touch hover
|
||||
if(pointerCount == 1){
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
mPrevX = e.getX();
|
||||
mPrevY = e.getY();
|
||||
break;
|
||||
}
|
||||
|
||||
// Scrolling feature
|
||||
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
|
||||
// The pointer count can never be 0, and it is not 1, therefore it is >= 2
|
||||
int hScroll = ((int) (e.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
|
||||
int vScroll = ((int) (e.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
|
||||
int hScroll = ((int) (e.getX() - mScrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
|
||||
int vScroll = ((int) (e.getY() - mScrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
|
||||
|
||||
if(vScroll != 0 || hScroll != 0){
|
||||
CallbackBridge.sendScroll(hScroll, vScroll);
|
||||
scrollLastInitialX = e.getX();
|
||||
scrollLastInitialY = e.getY();
|
||||
mScrollLastInitialX = e.getX();
|
||||
mScrollLastInitialY = e.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Camera movement
|
||||
int pointerIndex = e.findPointerIndex(currentPointerID);
|
||||
int pointerIndex = e.findPointerIndex(mCurrentPointerID);
|
||||
int hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
|
||||
// Start movement, due to new pointer or loss of pointer
|
||||
if (pointerIndex == -1 || lastPointerCount != pointerCount || !shouldBeDown) {
|
||||
if (pointerIndex == -1 || mLastPointerCount != pointerCount || !mShouldBeDown) {
|
||||
if(hudKeyHandled != -1) break; //No pointer attribution on hotbar
|
||||
|
||||
shouldBeDown = true;
|
||||
currentPointerID = e.getPointerId(0);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
mShouldBeDown = true;
|
||||
mCurrentPointerID = e.getPointerId(0);
|
||||
mPrevX = e.getX();
|
||||
mPrevY = e.getY();
|
||||
break;
|
||||
}
|
||||
// Continue movement as usual
|
||||
if(hudKeyHandled == -1){ //No camera on hotbar
|
||||
CallbackBridge.mouseX += (e.getX(pointerIndex) - prevX) * sensitivityFactor;
|
||||
CallbackBridge.mouseY += (e.getY(pointerIndex) - prevY) * sensitivityFactor;
|
||||
CallbackBridge.mouseX += (e.getX(pointerIndex) - mPrevX) * mSensitivityFactor;
|
||||
CallbackBridge.mouseY += (e.getY(pointerIndex) - mPrevY) * mSensitivityFactor;
|
||||
}
|
||||
|
||||
prevX = e.getX(pointerIndex);
|
||||
prevY = e.getY(pointerIndex);
|
||||
mPrevX = e.getX(pointerIndex);
|
||||
mPrevY = e.getY(pointerIndex);
|
||||
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
break;
|
||||
@@ -278,35 +218,35 @@ public class MinecraftGLView extends TextureView {
|
||||
boolean isTouchInHotbar = hudKeyHandled != -1;
|
||||
if (isTouchInHotbar) {
|
||||
sendKeyPress(hudKeyHandled);
|
||||
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
|
||||
if(hasDoubleTapped && hudKeyHandled == mLastHotbarKey){
|
||||
//Prevent double tapping Event on two different slots
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_F);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
||||
}
|
||||
|
||||
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 350);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
mLastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
}
|
||||
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
mPrevX = e.getX();
|
||||
mPrevY = e.getY();
|
||||
|
||||
if (CallbackBridge.isGrabbing()) {
|
||||
currentPointerID = e.getPointerId(0);
|
||||
mCurrentPointerID = e.getPointerId(0);
|
||||
// It cause hold left mouse while moving camera
|
||||
initialX = CallbackBridge.mouseX;
|
||||
initialY = CallbackBridge.mouseY;
|
||||
mInitialX = CallbackBridge.mouseX;
|
||||
mInitialY = CallbackBridge.mouseY;
|
||||
theHandler.sendEmptyMessageDelayed(MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
|
||||
}
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
mLastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
shouldBeDown = false;
|
||||
currentPointerID = -1;
|
||||
mShouldBeDown = false;
|
||||
mCurrentPointerID = -1;
|
||||
|
||||
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
|
||||
isTouchInHotbar = hudKeyHandled != -1;
|
||||
@@ -315,49 +255,49 @@ public class MinecraftGLView extends TextureView {
|
||||
|
||||
// Stop the dropping of items
|
||||
if (isTouchInHotbar) {
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q, 0, false);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q, 0, false);
|
||||
theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK);
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the mouse left button
|
||||
if(triggeredLeftMouseButton){
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
|
||||
triggeredLeftMouseButton = false;
|
||||
if(mTriggeredLeftMouseButton){
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
|
||||
mTriggeredLeftMouseButton = false;
|
||||
break;
|
||||
}
|
||||
theHandler.removeMessages(MSG_LEFT_MOUSE_BUTTON_CHECK);
|
||||
|
||||
// In case of a short click, just send a quick right click
|
||||
if(!LauncherPreferences.PREF_DISABLE_GESTURES &&
|
||||
MathUtils.dist(initialX, initialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
|
||||
MathUtils.dist(mInitialX, mInitialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
//TODO Hey we could have some sort of middle click detection ?
|
||||
|
||||
scrollLastInitialX = e.getX();
|
||||
scrollLastInitialY = e.getY();
|
||||
mScrollLastInitialX = e.getX();
|
||||
mScrollLastInitialY = e.getY();
|
||||
//Checking if we are pressing the hotbar to select the item
|
||||
hudKeyHandled = handleGuiBar((int)e.getX(e.getPointerCount()-1), (int) e.getY(e.getPointerCount()-1));
|
||||
if(hudKeyHandled != -1){
|
||||
sendKeyPress(hudKeyHandled);
|
||||
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
|
||||
if(hasDoubleTapped && hudKeyHandled == mLastHotbarKey){
|
||||
//Prevent double tapping Event on two different slots
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_F);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
||||
}
|
||||
}
|
||||
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
mLastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Actualise the pointer count
|
||||
lastPointerCount = e.getPointerCount();
|
||||
mLastPointerCount = e.getPointerCount();
|
||||
|
||||
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
@@ -374,11 +314,11 @@ public class MinecraftGLView extends TextureView {
|
||||
int mouseCursorIndex = -1;
|
||||
|
||||
if(Gamepad.isGamepadEvent(event)){
|
||||
if(gamepad == null){
|
||||
gamepad = new Gamepad(this, event.getDevice());
|
||||
if(mGamepad == null){
|
||||
mGamepad = new Gamepad(this, event.getDevice());
|
||||
}
|
||||
|
||||
gamepad.update(event);
|
||||
mGamepad.update(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -397,8 +337,8 @@ public class MinecraftGLView extends TextureView {
|
||||
}
|
||||
switch(event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * scaleFactor);
|
||||
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * scaleFactor);
|
||||
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * mScaleFactor);
|
||||
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * mScaleFactor);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
@@ -415,20 +355,20 @@ public class MinecraftGLView extends TextureView {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO MOVE THIS SOMEWHERE ELSE
|
||||
private boolean debugErrored = false;
|
||||
|
||||
|
||||
/** The input event for mouse with a captured pointer */
|
||||
@RequiresApi(26)
|
||||
@Override
|
||||
public boolean dispatchCapturedPointerEvent(MotionEvent e) {
|
||||
CallbackBridge.mouseX += (e.getX()*scaleFactor);
|
||||
CallbackBridge.mouseY += (e.getY()*scaleFactor);
|
||||
CallbackBridge.mouseX += (e.getX()* mScaleFactor);
|
||||
CallbackBridge.mouseY += (e.getY()* mScaleFactor);
|
||||
if(!CallbackBridge.isGrabbing()){
|
||||
releasePointerCapture();
|
||||
clearFocus();
|
||||
}
|
||||
|
||||
if (pointerDebugText.getVisibility() == View.VISIBLE && !debugErrored) {
|
||||
if (mPointerDebugTextView.getVisibility() == View.VISIBLE && !debugErrored) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
builder.append("PointerCapture debug\n");
|
||||
@@ -448,12 +388,12 @@ public class MinecraftGLView extends TextureView {
|
||||
debugErrored = true;
|
||||
builder.append("Error getting debug. The debug will be stopped!\n").append(Log.getStackTraceString(th));
|
||||
} finally {
|
||||
pointerDebugText.setText(builder.toString());
|
||||
mPointerDebugTextView.setText(builder.toString());
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
pointerDebugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
mPointerDebugTextView.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
@@ -506,7 +446,7 @@ public class MinecraftGLView extends TextureView {
|
||||
|
||||
|
||||
if(eventKeycode == KeyEvent.KEYCODE_BACK){
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -514,11 +454,11 @@ public class MinecraftGLView extends TextureView {
|
||||
|
||||
if(Gamepad.isGamepadEvent(event)){
|
||||
|
||||
if(gamepad == null){
|
||||
gamepad = new Gamepad(this, event.getDevice());
|
||||
if(mGamepad == null){
|
||||
mGamepad = new Gamepad(this, event.getDevice());
|
||||
}
|
||||
|
||||
gamepad.update(event);
|
||||
mGamepad.update(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -532,11 +472,66 @@ public class MinecraftGLView extends TextureView {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Get the mouse direction as a string */
|
||||
private String getMoving(float pos, boolean xOrY) {
|
||||
if (pos == 0) return "STOPPED";
|
||||
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
|
||||
return xOrY ? "LEFT" : "UP";
|
||||
|
||||
/** Initialize the view and all its settings */
|
||||
public void start(){
|
||||
// Add the pointer debug textview
|
||||
mPointerDebugTextView = new TextView(getContext());
|
||||
mPointerDebugTextView.setX(0);
|
||||
mPointerDebugTextView.setY(0);
|
||||
mPointerDebugTextView.setVisibility(GONE);
|
||||
((ViewGroup)getParent()).addView(mPointerDebugTextView);
|
||||
|
||||
setSurfaceTextureListener(new SurfaceTextureListener() {
|
||||
private boolean isCalled = false;
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
|
||||
windowWidth = Tools.getDisplayFriendlyRes(width, mScaleFactor);
|
||||
windowHeight = Tools.getDisplayFriendlyRes(height, mScaleFactor);
|
||||
texture.setDefaultBufferSize(windowWidth, windowHeight);
|
||||
|
||||
//Load Minecraft options:
|
||||
MCOptionUtils.load();
|
||||
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
|
||||
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
|
||||
MCOptionUtils.save();
|
||||
getMcScale();
|
||||
// Should we do that?
|
||||
if(isCalled) return;
|
||||
isCalled = true;
|
||||
|
||||
JREUtils.setupBridgeWindow(new Surface(texture));
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
if(mSurfaceReadyListener != null){
|
||||
mSurfaceReadyListener.isReady();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Tools.showError(getContext(), e, true);
|
||||
}
|
||||
}, "JVM Main thread").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
|
||||
windowWidth = Tools.getDisplayFriendlyRes(width, mScaleFactor);
|
||||
windowHeight = Tools.getDisplayFriendlyRes(height, mScaleFactor);
|
||||
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
|
||||
getMcScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
||||
texture.setDefaultBufferSize(windowWidth, windowHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Convert the mouse button, then send it
|
||||
@@ -546,13 +541,13 @@ public class MinecraftGLView extends TextureView {
|
||||
int glfwButton = -256;
|
||||
switch (button) {
|
||||
case MotionEvent.BUTTON_PRIMARY:
|
||||
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT;
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT;
|
||||
break;
|
||||
case MotionEvent.BUTTON_TERTIARY:
|
||||
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
break;
|
||||
case MotionEvent.BUTTON_SECONDARY:
|
||||
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT;
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT;
|
||||
break;
|
||||
}
|
||||
if(glfwButton == -256) return false;
|
||||
@@ -560,8 +555,6 @@ public class MinecraftGLView extends TextureView {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @return the hotbar key, given the position. -1 if no key are pressed */
|
||||
public int handleGuiBar(int x, int y) {
|
||||
if (!CallbackBridge.isGrabbing()) return -1;
|
||||
@@ -574,17 +567,12 @@ public class MinecraftGLView extends TextureView {
|
||||
int barX = (CallbackBridge.physicalWidth / 2) - (barWidth / 2);
|
||||
if(x < barX || x >= barX + barWidth) return -1;
|
||||
|
||||
return hotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
|
||||
}
|
||||
|
||||
/** Return the size, given the UI scale size */
|
||||
private int mcscale(int input) {
|
||||
return (int)((GUIScale * input)/scaleFactor);
|
||||
return sHotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
|
||||
}
|
||||
|
||||
/** Toggle the pointerDebugText visibility state */
|
||||
public void togglepointerDebugging() {
|
||||
pointerDebugText.setVisibility(pointerDebugText.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
|
||||
mPointerDebugTextView.setVisibility(mPointerDebugTextView.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/** A small interface called when the listener is ready for the first time */
|
||||
@@ -593,6 +581,19 @@ public class MinecraftGLView extends TextureView {
|
||||
}
|
||||
|
||||
public void setSurfaceReadyListener(SurfaceReadyListener listener){
|
||||
surfaceReadyListener = listener;
|
||||
mSurfaceReadyListener = listener;
|
||||
}
|
||||
|
||||
|
||||
/** Return the size, given the UI scale size */
|
||||
private int mcscale(int input) {
|
||||
return (int)((mGuiScale * input)/ mScaleFactor);
|
||||
}
|
||||
|
||||
/** Get the mouse direction as a string */
|
||||
private String getMoving(float pos, boolean xOrY) {
|
||||
if (pos == 0) return "STOPPED";
|
||||
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
|
||||
return xOrY ? "LEFT" : "UP";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,604 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import static net.kdt.pojavlaunch.BaseMainActivity.touchCharInput;
|
||||
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||
import static org.lwjgl.glfw.CallbackBridge.windowHeight;
|
||||
import static org.lwjgl.glfw.CallbackBridge.windowWidth;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.google.android.material.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
|
||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
import net.kdt.pojavlaunch.utils.JREUtils;
|
||||
import net.kdt.pojavlaunch.utils.MCOptionUtils;
|
||||
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
|
||||
/**
|
||||
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
|
||||
*/
|
||||
public class MinecraftLEGLView extends SurfaceView {
|
||||
/* Gamepad object for gamepad inputs, instantiated on need */
|
||||
private Gamepad gamepad = null;
|
||||
/* Pointer Debug textview, used to show info about the pointer state */
|
||||
private TextView pointerDebugText;
|
||||
/* Resolution scaler option, allow downsizing a window */
|
||||
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
/* Display properties, such as resolution and DPI */
|
||||
private final DisplayMetrics displayMetrics = Tools.getDisplayMetrics((Activity) getContext());
|
||||
/* Sensitivity, adjusted according to screen size */
|
||||
private final double sensitivityFactor = (1.4 * (1080f/ displayMetrics.heightPixels));
|
||||
/* Use to detect simple and double taps */
|
||||
private final TapDetector singleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
|
||||
private final TapDetector doubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
|
||||
/* MC GUI scale, listened by MCOptionUtils */
|
||||
private int GUIScale = getMcScale();
|
||||
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> GUIScale = getMcScale();
|
||||
/* Surface ready listener, used by the activity to launch minecraft */
|
||||
SurfaceReadyListener surfaceReadyListener = null;
|
||||
|
||||
/* List of hotbarKeys, used when clicking on the hotbar */
|
||||
private static final int[] hotbarKeys = {
|
||||
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
|
||||
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
|
||||
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
|
||||
/* Last hotbar button (0-9) registered */
|
||||
private int lastHotbarKey = -1;
|
||||
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
|
||||
private boolean shouldBeDown = false;
|
||||
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
|
||||
private int lastPointerCount = 0;
|
||||
/* Previous MotionEvent position, not scale */
|
||||
private float prevX, prevY;
|
||||
/* PointerID used for the moving camera */
|
||||
private int currentPointerID = -1000;
|
||||
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
|
||||
private float initialX, initialY;
|
||||
/* Last first pointer positions non-scaled, used to scroll distance */
|
||||
private float scrollLastInitialX, scrollLastInitialY;
|
||||
/* How much distance a finger has to go for touch sloppiness to be disabled */
|
||||
public static final int FINGER_STILL_THRESHOLD = (int) Tools.dpToPx(9);
|
||||
/* How much distance a finger has to go to scroll */
|
||||
public static final int FINGER_SCROLL_THRESHOLD = (int) Tools.dpToPx(6);
|
||||
/* Handle hotbar throw button and mouse mining button */
|
||||
public static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
|
||||
public static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029;
|
||||
private final Handler theHandler = new Handler(Looper.getMainLooper()) {
|
||||
public void handleMessage(Message msg) {
|
||||
if(msg.what == MSG_LEFT_MOUSE_BUTTON_CHECK) {
|
||||
if (LauncherPreferences.PREF_DISABLE_GESTURES) return;
|
||||
float x = CallbackBridge.mouseX;
|
||||
float y = CallbackBridge.mouseY;
|
||||
if (CallbackBridge.isGrabbing() &&
|
||||
MathUtils.dist(x, y, initialX, initialY) < FINGER_STILL_THRESHOLD) {
|
||||
triggeredLeftMouseButton = true;
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(msg.what == MSG_DROP_ITEM_BUTTON_CHECK) {
|
||||
if(CallbackBridge.isGrabbing()){
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q);
|
||||
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 600);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
/* Whether the button was triggered, used by the handler */
|
||||
private static boolean triggeredLeftMouseButton = false;
|
||||
|
||||
|
||||
public MinecraftLEGLView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MinecraftLEGLView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
//Fixes freeform and dex mode having transparent glass,
|
||||
//since it forces android to used the background color of the view/layout behind it.
|
||||
//setOpaque(false);
|
||||
setFocusable(true);
|
||||
|
||||
MCOptionUtils.addMCOptionListener(GUIScaleListener);
|
||||
}
|
||||
|
||||
/** Initialize the view and all its settings */
|
||||
public void start(){
|
||||
// Add the pointer debug textview
|
||||
pointerDebugText = new TextView(getContext());
|
||||
pointerDebugText.setX(0);
|
||||
pointerDebugText.setY(0);
|
||||
pointerDebugText.setVisibility(GONE);
|
||||
((ViewGroup)getParent()).addView(pointerDebugText);
|
||||
|
||||
|
||||
getHolder().addCallback(new SurfaceHolder.Callback() {
|
||||
private boolean isCalled = false;
|
||||
@Override
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
|
||||
//Load Minecraft options:
|
||||
MCOptionUtils.load();
|
||||
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
|
||||
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
|
||||
MCOptionUtils.save();
|
||||
getMcScale();
|
||||
// Should we do that?
|
||||
if(isCalled) return;
|
||||
isCalled = true;
|
||||
|
||||
getHolder().setFixedSize(windowWidth, windowHeight);
|
||||
|
||||
|
||||
JREUtils.setupBridgeWindow(getHolder().getSurface());
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
if(surfaceReadyListener != null){
|
||||
surfaceReadyListener.isReady();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Tools.showError(getContext(), e, true);
|
||||
}
|
||||
}, "JVM Main thread").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||
windowWidth = Tools.getDisplayFriendlyRes(displayMetrics.widthPixels, scaleFactor);
|
||||
windowHeight = Tools.getDisplayFriendlyRes(displayMetrics.heightPixels, scaleFactor);
|
||||
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
|
||||
getMcScale();
|
||||
Toast.makeText(getContext(), "width: " + width, Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getContext(), "height: " + height, Toast.LENGTH_SHORT).show();
|
||||
getHolder().setFixedSize(windowWidth, windowHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The touch event for both grabbed an non-grabbed mouse state on the touch screen
|
||||
* Does not cover the virtual mouse touchpad
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
// Looking for a mouse to handle, won't have an effect if no mouse exists.
|
||||
for (int i = 0; i < e.getPointerCount(); i++) {
|
||||
if (e.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE) continue;
|
||||
|
||||
// Mouse found
|
||||
if(CallbackBridge.isGrabbing()) return false;
|
||||
CallbackBridge.sendCursorPos( e.getX(i) * scaleFactor, e.getY(i) * scaleFactor);
|
||||
return true; //mouse event handled successfully
|
||||
}
|
||||
|
||||
// System.out.println("Pre touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked()));
|
||||
|
||||
//Getting scaled position from the event
|
||||
/* Tells if a double tap happened [MOUSE GRAB ONLY]. Doesn't tell where though. */
|
||||
if(!CallbackBridge.isGrabbing()) {
|
||||
CallbackBridge.mouseX = (e.getX() * scaleFactor);
|
||||
CallbackBridge.mouseY = (e.getY() * scaleFactor);
|
||||
//One android click = one MC click
|
||||
if(singleTapDetector.onTouchEvent(e)){
|
||||
CallbackBridge.putMouseEventWithCoords(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check double tap state, used for the hotbar
|
||||
boolean hasDoubleTapped = doubleTapDetector.onTouchEvent(e);
|
||||
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int pointerCount = e.getPointerCount();
|
||||
|
||||
// In-menu interactions
|
||||
if(!CallbackBridge.isGrabbing()){
|
||||
|
||||
// Touch hover
|
||||
if(pointerCount == 1){
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
break;
|
||||
}
|
||||
|
||||
// Scrolling feature
|
||||
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
|
||||
// The pointer count can never be 0, and it is not 1, therefore it is >= 2
|
||||
int hScroll = ((int) (e.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
|
||||
int vScroll = ((int) (e.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
|
||||
|
||||
if(vScroll != 0 || hScroll != 0){
|
||||
CallbackBridge.sendScroll(hScroll, vScroll);
|
||||
scrollLastInitialX = e.getX();
|
||||
scrollLastInitialY = e.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Camera movement
|
||||
int pointerIndex = e.findPointerIndex(currentPointerID);
|
||||
int hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
|
||||
// Start movement, due to new pointer or loss of pointer
|
||||
if (pointerIndex == -1 || lastPointerCount != pointerCount || !shouldBeDown) {
|
||||
if(hudKeyHandled != -1) break; //No pointer attribution on hotbar
|
||||
|
||||
shouldBeDown = true;
|
||||
currentPointerID = e.getPointerId(0);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
break;
|
||||
}
|
||||
// Continue movement as usual
|
||||
if(hudKeyHandled == -1){ //No camera on hotbar
|
||||
CallbackBridge.mouseX += (e.getX(pointerIndex) - prevX) * sensitivityFactor;
|
||||
CallbackBridge.mouseY += (e.getY(pointerIndex) - prevY) * sensitivityFactor;
|
||||
}
|
||||
|
||||
prevX = e.getX(pointerIndex);
|
||||
prevY = e.getY(pointerIndex);
|
||||
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN: // 0
|
||||
CallbackBridge.sendPrepareGrabInitialPos();
|
||||
|
||||
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
|
||||
boolean isTouchInHotbar = hudKeyHandled != -1;
|
||||
if (isTouchInHotbar) {
|
||||
sendKeyPress(hudKeyHandled);
|
||||
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
|
||||
//Prevent double tapping Event on two different slots
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
||||
}
|
||||
|
||||
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 350);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
}
|
||||
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
prevX = e.getX();
|
||||
prevY = e.getY();
|
||||
|
||||
if (CallbackBridge.isGrabbing()) {
|
||||
currentPointerID = e.getPointerId(0);
|
||||
// It cause hold left mouse while moving camera
|
||||
initialX = CallbackBridge.mouseX;
|
||||
initialY = CallbackBridge.mouseY;
|
||||
theHandler.sendEmptyMessageDelayed(MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
|
||||
}
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
shouldBeDown = false;
|
||||
currentPointerID = -1;
|
||||
|
||||
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
|
||||
isTouchInHotbar = hudKeyHandled != -1;
|
||||
// We only treat in world events
|
||||
if (!CallbackBridge.isGrabbing()) break;
|
||||
|
||||
// Stop the dropping of items
|
||||
if (isTouchInHotbar) {
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q, 0, false);
|
||||
theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK);
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the mouse left button
|
||||
if(triggeredLeftMouseButton){
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
|
||||
triggeredLeftMouseButton = false;
|
||||
break;
|
||||
}
|
||||
theHandler.removeMessages(MSG_LEFT_MOUSE_BUTTON_CHECK);
|
||||
|
||||
// In case of a short click, just send a quick right click
|
||||
if(!LauncherPreferences.PREF_DISABLE_GESTURES &&
|
||||
MathUtils.dist(initialX, initialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
//TODO Hey we could have some sort of middle click detection ?
|
||||
|
||||
scrollLastInitialX = e.getX();
|
||||
scrollLastInitialY = e.getY();
|
||||
//Checking if we are pressing the hotbar to select the item
|
||||
hudKeyHandled = handleGuiBar((int)e.getX(e.getPointerCount()-1), (int) e.getY(e.getPointerCount()-1));
|
||||
if(hudKeyHandled != -1){
|
||||
sendKeyPress(hudKeyHandled);
|
||||
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
|
||||
//Prevent double tapping Event on two different slots
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
||||
}
|
||||
}
|
||||
|
||||
lastHotbarKey = hudKeyHandled;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Actualise the pointer count
|
||||
lastPointerCount = e.getPointerCount();
|
||||
|
||||
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event for mouse/joystick movements
|
||||
* We don't do the gamepad right now.
|
||||
*/
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
int mouseCursorIndex = -1;
|
||||
|
||||
if(Gamepad.isGamepadEvent(event)){
|
||||
if(gamepad == null){
|
||||
gamepad = new Gamepad(this, event.getDevice());
|
||||
}
|
||||
|
||||
gamepad.update(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
for(int i = 0; i < event.getPointerCount(); i++) {
|
||||
if(event.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE) continue;
|
||||
// Mouse found
|
||||
mouseCursorIndex = i;
|
||||
break;
|
||||
}
|
||||
if(mouseCursorIndex == -1) return false; // we cant consoom that, theres no mice!
|
||||
if(CallbackBridge.isGrabbing()) {
|
||||
if(BaseMainActivity.isAndroid8OrHigher()){
|
||||
requestFocus();
|
||||
requestPointerCapture();
|
||||
}
|
||||
}
|
||||
switch(event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * scaleFactor);
|
||||
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * scaleFactor);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
return true;
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
CallbackBridge.sendScroll((double) event.getAxisValue(MotionEvent.AXIS_VSCROLL), (double) event.getAxisValue(MotionEvent.AXIS_HSCROLL));
|
||||
return true;
|
||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
||||
return sendMouseButtonUnconverted(event.getActionButton(),true);
|
||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
||||
return sendMouseButtonUnconverted(event.getActionButton(),false);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO MOVE THIS SOMEWHERE ELSE
|
||||
private boolean debugErrored = false;
|
||||
/** The input event for mouse with a captured pointer */
|
||||
@RequiresApi(26)
|
||||
@Override
|
||||
public boolean dispatchCapturedPointerEvent(MotionEvent e) {
|
||||
CallbackBridge.mouseX += (e.getX()*scaleFactor);
|
||||
CallbackBridge.mouseY += (e.getY()*scaleFactor);
|
||||
if(!CallbackBridge.isGrabbing()){
|
||||
releasePointerCapture();
|
||||
clearFocus();
|
||||
}
|
||||
|
||||
if (pointerDebugText.getVisibility() == View.VISIBLE && !debugErrored) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
builder.append("PointerCapture debug\n");
|
||||
builder.append("MotionEvent=").append(e.getActionMasked()).append("\n");
|
||||
builder.append("PressingBtn=").append(MotionEvent.class.getDeclaredMethod("buttonStateToString").invoke(null, e.getButtonState())).append("\n\n");
|
||||
|
||||
builder.append("PointerX=").append(e.getX()).append("\n");
|
||||
builder.append("PointerY=").append(e.getY()).append("\n");
|
||||
builder.append("RawX=").append(e.getRawX()).append("\n");
|
||||
builder.append("RawY=").append(e.getRawY()).append("\n\n");
|
||||
|
||||
builder.append("XPos=").append(CallbackBridge.mouseX).append("\n");
|
||||
builder.append("YPos=").append(CallbackBridge.mouseY).append("\n\n");
|
||||
builder.append("MovingX=").append(getMoving(e.getX(), true)).append("\n");
|
||||
builder.append("MovingY=").append(getMoving(e.getY(), false)).append("\n");
|
||||
} catch (Throwable th) {
|
||||
debugErrored = true;
|
||||
builder.append("Error getting debug. The debug will be stopped!\n").append(Log.getStackTraceString(th));
|
||||
} finally {
|
||||
pointerDebugText.setText(builder.toString());
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
pointerDebugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
return true;
|
||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
||||
return sendMouseButtonUnconverted(e.getActionButton(), true);
|
||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
||||
return sendMouseButtonUnconverted(e.getActionButton(), false);
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
CallbackBridge.sendScroll(e.getAxisValue(MotionEvent.AXIS_HSCROLL), e.getAxisValue(MotionEvent.AXIS_VSCROLL));
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** The event for keyboard/ gamepad button inputs */
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
//Toast.makeText(this, event.toString(),Toast.LENGTH_SHORT).show();
|
||||
//Toast.makeText(this, event.getDevice().toString(), Toast.LENGTH_SHORT).show();
|
||||
|
||||
//Filtering useless events by order of probability
|
||||
if((event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK) return true;
|
||||
int eventKeycode = event.getKeyCode();
|
||||
if(eventKeycode == KeyEvent.KEYCODE_UNKNOWN) return true;
|
||||
if(eventKeycode == KeyEvent.KEYCODE_VOLUME_DOWN) return false;
|
||||
if(eventKeycode == KeyEvent.KEYCODE_VOLUME_UP) return false;
|
||||
if(event.getRepeatCount() != 0) return true;
|
||||
if(event.getAction() == KeyEvent.ACTION_MULTIPLE) return true;
|
||||
|
||||
//Toast.makeText(this, "FIRST VERIF PASSED", Toast.LENGTH_SHORT).show();
|
||||
|
||||
//Sometimes, key events comes from SOME keys of the software keyboard
|
||||
//Even weirder, is is unknown why a key or another is selected to trigger a keyEvent
|
||||
if((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD){
|
||||
if(eventKeycode == KeyEvent.KEYCODE_ENTER) return true; //We already listen to it.
|
||||
touchCharInput.dispatchKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
//Toast.makeText(this, "SECOND VERIF PASSED", Toast.LENGTH_SHORT).show();
|
||||
|
||||
|
||||
//Sometimes, key events may come from the mouse
|
||||
if(event.getDevice() != null
|
||||
&& ( (event.getSource() & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE
|
||||
|| (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) ){
|
||||
//Toast.makeText(this, "THE EVENT COMES FROM A MOUSE", Toast.LENGTH_SHORT).show();
|
||||
|
||||
|
||||
if(eventKeycode == KeyEvent.KEYCODE_BACK){
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
System.out.println(event);
|
||||
|
||||
if(Gamepad.isGamepadEvent(event)){
|
||||
|
||||
if(gamepad == null){
|
||||
gamepad = new Gamepad(this, event.getDevice());
|
||||
}
|
||||
|
||||
gamepad.update(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
int index = EfficientAndroidLWJGLKeycode.getIndexByKey(eventKeycode);
|
||||
if(index >= 0) {
|
||||
//Toast.makeText(this,"THIS IS A KEYBOARD EVENT !", Toast.LENGTH_SHORT).show();
|
||||
EfficientAndroidLWJGLKeycode.execKey(event, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Get the mouse direction as a string */
|
||||
private String getMoving(float pos, boolean xOrY) {
|
||||
if (pos == 0) return "STOPPED";
|
||||
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
|
||||
return xOrY ? "LEFT" : "UP";
|
||||
}
|
||||
|
||||
/** Convert the mouse button, then send it
|
||||
* @return Whether the event was processed
|
||||
*/
|
||||
public static boolean sendMouseButtonUnconverted(int button, boolean status) {
|
||||
int glfwButton = -256;
|
||||
switch (button) {
|
||||
case MotionEvent.BUTTON_PRIMARY:
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT;
|
||||
break;
|
||||
case MotionEvent.BUTTON_TERTIARY:
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
break;
|
||||
case MotionEvent.BUTTON_SECONDARY:
|
||||
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT;
|
||||
break;
|
||||
}
|
||||
if(glfwButton == -256) return false;
|
||||
sendMouseButton(glfwButton, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @return the hotbar key, given the position. -1 if no key are pressed */
|
||||
public int handleGuiBar(int x, int y) {
|
||||
if (!CallbackBridge.isGrabbing()) return -1;
|
||||
|
||||
int barHeight = mcscale(20);
|
||||
int barY = CallbackBridge.physicalHeight - barHeight;
|
||||
if(y < barY) return -1;
|
||||
|
||||
int barWidth = mcscale(180);
|
||||
int barX = (CallbackBridge.physicalWidth / 2) - (barWidth / 2);
|
||||
if(x < barX || x >= barX + barWidth) return -1;
|
||||
|
||||
return hotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
|
||||
}
|
||||
|
||||
/** Return the size, given the UI scale size */
|
||||
private int mcscale(int input) {
|
||||
return (int)((GUIScale * input)/scaleFactor);
|
||||
}
|
||||
|
||||
/** Toggle the pointerDebugText visibility state */
|
||||
public void togglepointerDebugging() {
|
||||
pointerDebugText.setVisibility(pointerDebugText.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/** A small interface called when the listener is ready for the first time */
|
||||
public interface SurfaceReadyListener {
|
||||
void isReady();
|
||||
}
|
||||
|
||||
public void setSurfaceReadyListener(SurfaceReadyListener listener){
|
||||
surfaceReadyListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -14,40 +14,37 @@ import java.util.*;
|
||||
|
||||
import net.kdt.pojavlaunch.utils.*;
|
||||
|
||||
public class PojavApplication extends Application
|
||||
{
|
||||
public class PojavApplication extends Application {
|
||||
public static String CRASH_REPORT_TAG = "PojavCrashReport";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable th) {
|
||||
boolean storagePermAllowed = Build.VERSION.SDK_INT < 23 || ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt");
|
||||
try {
|
||||
// Write to file, since some devices may not able to show error
|
||||
crashFile.getParentFile().mkdirs();
|
||||
crashFile.createNewFile();
|
||||
PrintStream crashStream = new PrintStream(crashFile);
|
||||
crashStream.append("PojavLauncher crash report\n");
|
||||
crashStream.append(" - Time: " + DateFormat.getDateTimeInstance().format(new Date()) + "\n");
|
||||
crashStream.append(" - Device: " + Build.PRODUCT + " " + Build.MODEL + "\n");
|
||||
crashStream.append(" - Android version: " + Build.VERSION.RELEASE + "\n");
|
||||
crashStream.append(" - Crash stack trace:\n");
|
||||
crashStream.append(" - Launcher version: " + BuildConfig.VERSION_NAME + "\n");
|
||||
crashStream.append(Log.getStackTraceString(th));
|
||||
crashStream.close();
|
||||
} catch (Throwable th2) {
|
||||
Log.e(CRASH_REPORT_TAG, " - Exception attempt saving crash stack trace:", th2);
|
||||
Log.e(CRASH_REPORT_TAG, " - The crash stack trace was:", th);
|
||||
}
|
||||
|
||||
FatalErrorActivity.showError(PojavApplication.this, crashFile.getAbsolutePath(), storagePermAllowed, th);
|
||||
// android.os.Process.killProcess(android.os.Process.myPid());
|
||||
|
||||
BaseMainActivity.fullyExit();
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, th) -> {
|
||||
boolean storagePermAllowed = Build.VERSION.SDK_INT < 23 ||
|
||||
ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt");
|
||||
try {
|
||||
// Write to file, since some devices may not able to show error
|
||||
crashFile.getParentFile().mkdirs();
|
||||
crashFile.createNewFile();
|
||||
PrintStream crashStream = new PrintStream(crashFile);
|
||||
crashStream.append("PojavLauncher crash report\n");
|
||||
crashStream.append(" - Time: " + DateFormat.getDateTimeInstance().format(new Date()) + "\n");
|
||||
crashStream.append(" - Device: " + Build.PRODUCT + " " + Build.MODEL + "\n");
|
||||
crashStream.append(" - Android version: " + Build.VERSION.RELEASE + "\n");
|
||||
crashStream.append(" - Crash stack trace:\n");
|
||||
crashStream.append(" - Launcher version: " + BuildConfig.VERSION_NAME + "\n");
|
||||
crashStream.append(Log.getStackTraceString(th));
|
||||
crashStream.close();
|
||||
} catch (Throwable throwable) {
|
||||
Log.e(CRASH_REPORT_TAG, " - Exception attempt saving crash stack trace:", throwable);
|
||||
Log.e(CRASH_REPORT_TAG, " - The crash stack trace was:", th);
|
||||
}
|
||||
|
||||
FatalErrorActivity.showError(PojavApplication.this, crashFile.getAbsolutePath(), storagePermAllowed, th);
|
||||
// android.os.Process.killProcess(android.os.Process.myPid());
|
||||
|
||||
BaseMainActivity.fullyExit();
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -70,10 +67,9 @@ public class PojavApplication extends Application
|
||||
.concat("/x86");
|
||||
}
|
||||
|
||||
|
||||
} catch (Throwable th) {
|
||||
} catch (Throwable throwable) {
|
||||
Intent ferrorIntent = new Intent(this, FatalErrorActivity.class);
|
||||
ferrorIntent.putExtra("throwable", th);
|
||||
ferrorIntent.putExtra("throwable", throwable);
|
||||
startActivity(ferrorIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class PojavLauncherActivity extends BaseLauncherActivity
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.launcher_main_v4);
|
||||
setContentView(R.layout.activity_pojav_launcher);
|
||||
|
||||
//Boilerplate linking/initialisation
|
||||
viewPager = findViewById(R.id.launchermainTabPager);
|
||||
@@ -288,7 +288,7 @@ public class PojavLauncherActivity extends BaseLauncherActivity
|
||||
accountFaceImageView.setImageBitmap(mProfile.getSkinFace());
|
||||
|
||||
//TODO FULL BACKGROUND LOGIN
|
||||
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_offline : R.string.mcl_account_connected);
|
||||
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_local : R.string.mcl_account_connected);
|
||||
} catch(Exception e) {
|
||||
mProfile = new MinecraftAccount();
|
||||
Tools.showError(this, e, true);
|
||||
|
||||
@@ -10,10 +10,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -22,7 +19,6 @@ import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -48,8 +44,6 @@ import androidx.core.content.ContextCompat;
|
||||
import net.kdt.pojavlaunch.authenticator.microsoft.MicrosoftAuthTask;
|
||||
import net.kdt.pojavlaunch.authenticator.microsoft.ui.MicrosoftLoginGUIActivity;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.InvalidateTokenTask;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.LoginListener;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.LoginTask;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
|
||||
import net.kdt.pojavlaunch.customcontrols.CustomControls;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
|
||||
@@ -69,15 +63,13 @@ import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PojavLoginActivity extends BaseActivity
|
||||
// MineActivity
|
||||
{
|
||||
public class PojavLoginActivity extends BaseActivity {
|
||||
private final Object mLockStoragePerm = new Object();
|
||||
private final Object mLockSelectJRE = new Object();
|
||||
|
||||
private EditText edit2, edit3;
|
||||
private EditText edit2;
|
||||
private final int REQUEST_STORAGE_REQUEST_CODE = 1;
|
||||
private CheckBox sRemember, sOffline;
|
||||
private CheckBox sRemember;
|
||||
private TextView startupTextView;
|
||||
private SharedPreferences firstLaunchPrefs;
|
||||
private MinecraftAccount mProfile = null;
|
||||
@@ -173,7 +165,7 @@ public class PojavLoginActivity extends BaseActivity
|
||||
}
|
||||
}
|
||||
private void uiInit() {
|
||||
setContentView(R.layout.launcher_login_v3);
|
||||
setContentView(R.layout.activity_pojav_login);
|
||||
|
||||
Spinner spinnerChgLang = findViewById(R.id.login_spinner_language);
|
||||
|
||||
@@ -243,15 +235,8 @@ public class PojavLoginActivity extends BaseActivity
|
||||
});
|
||||
|
||||
edit2 = (EditText) findViewById(R.id.login_edit_email);
|
||||
edit3 = (EditText) findViewById(R.id.login_edit_password);
|
||||
|
||||
sRemember = findViewById(R.id.login_switch_remember);
|
||||
sOffline = findViewById(R.id.login_switch_offline);
|
||||
sOffline.setOnCheckedChangeListener((p1, p2) -> {
|
||||
// May delete later
|
||||
edit3.setEnabled(!p2);
|
||||
});
|
||||
|
||||
isSkipInit = true;
|
||||
}
|
||||
|
||||
@@ -496,14 +481,14 @@ public class PojavLoginActivity extends BaseActivity
|
||||
|
||||
final Dialog accountDialog = new Dialog(PojavLoginActivity.this);
|
||||
|
||||
accountDialog.setContentView(R.layout.simple_account_list_holder);
|
||||
accountDialog.setContentView(R.layout.dialog_select_account);
|
||||
|
||||
LinearLayout accountListLayout = accountDialog.findViewById(R.id.accountListLayout);
|
||||
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
for (int accountIndex = 0; accountIndex < accountArr.length; accountIndex++) {
|
||||
String s = accountArr[accountIndex];
|
||||
View child = inflater.inflate(R.layout.simple_account_list_item, accountListLayout,false);
|
||||
View child = inflater.inflate(R.layout.item_minecraft_account, accountListLayout,false);
|
||||
TextView accountName = child.findViewById(R.id.accountitem_text_name);
|
||||
ImageButton removeButton = child.findViewById(R.id.accountitem_button_remove);
|
||||
ImageView imageView = child.findViewById(R.id.account_head);
|
||||
@@ -535,11 +520,9 @@ public class PojavLoginActivity extends BaseActivity
|
||||
};
|
||||
|
||||
MinecraftAccount acc = MinecraftAccount.load(selectedAccName);
|
||||
if (acc.isMicrosoft){
|
||||
if (acc.accessToken.length() >= 5){
|
||||
new MicrosoftAuthTask(PojavLoginActivity.this, authListener)
|
||||
.execute("true", acc.msaRefreshToken);
|
||||
} else if (acc.accessToken.length() >= 5) {
|
||||
PojavProfile.updateTokens(PojavLoginActivity.this, selectedAccName, authListener);
|
||||
} else {
|
||||
accountDialog.dismiss();
|
||||
PojavProfile.launch(PojavLoginActivity.this, selectedAccName);
|
||||
@@ -580,7 +563,7 @@ public class PojavLoginActivity extends BaseActivity
|
||||
accountDialog.show();
|
||||
}
|
||||
|
||||
private MinecraftAccount loginOffline() {
|
||||
private MinecraftAccount loginLocal() {
|
||||
new File(Tools.DIR_ACCOUNT_OLD).mkdir();
|
||||
|
||||
String text = edit2.getText().toString();
|
||||
@@ -590,8 +573,6 @@ public class PojavLoginActivity extends BaseActivity
|
||||
edit2.setError(getString(R.string.login_error_invalid_username));
|
||||
} else if (new File(Tools.DIR_ACCOUNT_NEW + "/" + text + ".json").exists()) {
|
||||
edit2.setError(getString(R.string.login_error_exist_username));
|
||||
} else if (!edit3.getText().toString().isEmpty()) {
|
||||
edit3.setError(getString(R.string.login_error_offline_password));
|
||||
} else {
|
||||
MinecraftAccount builder = new MinecraftAccount();
|
||||
builder.isMicrosoft = false;
|
||||
@@ -605,43 +586,8 @@ public class PojavLoginActivity extends BaseActivity
|
||||
|
||||
public void loginMC(final View v)
|
||||
{
|
||||
|
||||
if (sOffline.isChecked()) {
|
||||
mProfile = loginOffline();
|
||||
playProfile(false);
|
||||
} else {
|
||||
ProgressBar prb = findViewById(R.id.launcherAccProgress);
|
||||
new LoginTask().setLoginListener(new LoginListener(){
|
||||
|
||||
|
||||
@Override
|
||||
public void onBeforeLogin() {
|
||||
v.setEnabled(false);
|
||||
prb.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginDone(String[] result) {
|
||||
if(result[0].equals("ERROR")){
|
||||
Tools.dialogOnUiThread(PojavLoginActivity.this,
|
||||
getResources().getString(R.string.global_error), strArrToString(result));
|
||||
} else{
|
||||
MinecraftAccount builder = new MinecraftAccount();
|
||||
builder.accessToken = result[1];
|
||||
builder.clientToken = result[2];
|
||||
builder.profileId = result[3];
|
||||
builder.username = result[4];
|
||||
builder.updateSkinFace();
|
||||
mProfile = builder;
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
v.setEnabled(true);
|
||||
prb.setVisibility(View.GONE);
|
||||
playProfile(false);
|
||||
});
|
||||
}
|
||||
}).execute(edit2.getText().toString(), edit3.getText().toString());
|
||||
}
|
||||
mProfile = loginLocal();
|
||||
playProfile(false);
|
||||
}
|
||||
|
||||
private void playProfile(boolean notOnLogin) {
|
||||
|
||||
@@ -6,8 +6,7 @@ import net.kdt.pojavlaunch.value.*;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class PojavMigrator
|
||||
{
|
||||
public class PojavMigrator {
|
||||
public static void migrateAccountData(Context ctx) {
|
||||
File oldAccDir = new File(Tools.DIR_ACCOUNT_OLD);
|
||||
if (oldAccDir.exists() && oldAccDir.isDirectory()) {
|
||||
|
||||
@@ -8,14 +8,11 @@ import android.util.Log;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshTokenTask;
|
||||
import net.kdt.pojavlaunch.value.MinecraftAccount;
|
||||
|
||||
public class PojavProfile
|
||||
{
|
||||
private static String PROFILE_PREF = "pojav_profile";
|
||||
private static String PROFILE_PREF_FILE = "file";
|
||||
public class PojavProfile {
|
||||
private static final String PROFILE_PREF = "pojav_profile";
|
||||
private static final String PROFILE_PREF_FILE = "file";
|
||||
public static String PROFILE_PREF_TEMP_CONTENT = "tempContent";
|
||||
|
||||
public static SharedPreferences getPrefs(Context ctx) {
|
||||
@@ -33,26 +30,26 @@ public class PojavProfile
|
||||
|
||||
public static MinecraftAccount getTempProfileContent() {
|
||||
try {
|
||||
MinecraftAccount acc = MinecraftAccount.parse(Tools.read(Tools.DIR_DATA+"/cache/tempacc.json"));
|
||||
if (acc.accessToken == null) {
|
||||
acc.accessToken = "0";
|
||||
MinecraftAccount account = MinecraftAccount.parse(Tools.read(Tools.DIR_DATA+"/cache/tempacc.json"));
|
||||
if (account.accessToken == null) {
|
||||
account.accessToken = "0";
|
||||
}
|
||||
if (acc.clientToken == null) {
|
||||
acc.clientToken = "0";
|
||||
if (account.clientToken == null) {
|
||||
account.clientToken = "0";
|
||||
}
|
||||
if (acc.profileId == null) {
|
||||
acc.profileId = "00000000-0000-0000-0000-000000000000";
|
||||
if (account.profileId == null) {
|
||||
account.profileId = "00000000-0000-0000-0000-000000000000";
|
||||
}
|
||||
if (acc.username == null) {
|
||||
acc.username = "0";
|
||||
if (account.username == null) {
|
||||
account.username = "0";
|
||||
}
|
||||
if (acc.selectedVersion == null) {
|
||||
acc.selectedVersion = "1.7.10";
|
||||
if (account.selectedVersion == null) {
|
||||
account.selectedVersion = "1.7.10";
|
||||
}
|
||||
if (acc.msaRefreshToken == null) {
|
||||
acc.msaRefreshToken = "0";
|
||||
if (account.msaRefreshToken == null) {
|
||||
account.msaRefreshToken = "0";
|
||||
}
|
||||
return acc;
|
||||
return account;
|
||||
}catch (IOException e) {
|
||||
Log.e(MinecraftAccount.class.getName(), "Caught an exception while loading the temporary profile",e);
|
||||
return null;
|
||||
@@ -104,8 +101,4 @@ public class PojavProfile
|
||||
Intent intent = new Intent(ctx, PojavLauncherActivity.class); //MCLauncherActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void updateTokens(final Activity ctx, final String name, RefreshListener listen) throws Exception {
|
||||
new RefreshTokenTask(ctx, listen).execute(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ package net.kdt.pojavlaunch;
|
||||
import android.view.*;
|
||||
import android.view.GestureDetector.*;
|
||||
|
||||
public class SingleTapConfirm extends SimpleOnGestureListener
|
||||
{
|
||||
public class SingleTapConfirm extends SimpleOnGestureListener {
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent event) {
|
||||
return true;
|
||||
|
||||
@@ -22,10 +22,10 @@ public class TapDetector {
|
||||
private final static int TAP_MAX_DELTA_MS = 300;
|
||||
private final static int TAP_SLOP_SQUARE_PX = (int) Math.pow(Tools.dpToPx(100), 2);
|
||||
|
||||
private final int tapNumberToDetect;
|
||||
private int currentTapNumber = 0;
|
||||
private final int mTapNumberToDetect;
|
||||
private int mCurrentTapNumber = 0;
|
||||
|
||||
private final int detectionMethod;
|
||||
private final int mDetectionMethod;
|
||||
|
||||
private long mLastEventTime = 0;
|
||||
private float mLastX = 9999;
|
||||
@@ -36,9 +36,9 @@ public class TapDetector {
|
||||
* @param detectionMethod Method used to detect touches. See DETECTION_METHOD constants above.
|
||||
*/
|
||||
public TapDetector(int tapNumberToDetect, int detectionMethod){
|
||||
this.detectionMethod = detectionMethod;
|
||||
this.mDetectionMethod = detectionMethod;
|
||||
//We expect both ACTION_DOWN and ACTION_UP for the DETECTION_METHOD_BOTH
|
||||
this.tapNumberToDetect = detectBothTouch() ? 2*tapNumberToDetect : tapNumberToDetect;
|
||||
this.mTapNumberToDetect = detectBothTouch() ? 2*tapNumberToDetect : tapNumberToDetect;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,17 +78,17 @@ public class TapDetector {
|
||||
mLastY = eventY;
|
||||
|
||||
//Check for high enough speed and precision
|
||||
if(currentTapNumber > 0){
|
||||
if(mCurrentTapNumber > 0){
|
||||
if ((deltaTime < TAP_MIN_DELTA_MS || deltaTime > TAP_MAX_DELTA_MS) ||
|
||||
((deltaX*deltaX + deltaY*deltaY) > TAP_SLOP_SQUARE_PX)) {
|
||||
// We invalidate previous taps, not this one though
|
||||
currentTapNumber = 0;
|
||||
mCurrentTapNumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//A worthy tap happened
|
||||
currentTapNumber += 1;
|
||||
if(currentTapNumber >= tapNumberToDetect){
|
||||
mCurrentTapNumber += 1;
|
||||
if(mCurrentTapNumber >= mTapNumberToDetect){
|
||||
resetTapDetectionState();
|
||||
return true;
|
||||
}
|
||||
@@ -101,22 +101,21 @@ public class TapDetector {
|
||||
* Reset the double tap values.
|
||||
*/
|
||||
private void resetTapDetectionState(){
|
||||
currentTapNumber = 0;
|
||||
mCurrentTapNumber = 0;
|
||||
mLastEventTime = 0;
|
||||
mLastX = 9999;
|
||||
mLastY = 9999;
|
||||
}
|
||||
|
||||
|
||||
private boolean detectDownTouch(){
|
||||
return (detectionMethod & DETECTION_METHOD_DOWN) == DETECTION_METHOD_DOWN;
|
||||
return (mDetectionMethod & DETECTION_METHOD_DOWN) == DETECTION_METHOD_DOWN;
|
||||
}
|
||||
|
||||
private boolean detectUpTouch(){
|
||||
return (detectionMethod & DETECTION_METHOD_UP) == DETECTION_METHOD_UP;
|
||||
return (mDetectionMethod & DETECTION_METHOD_UP) == DETECTION_METHOD_UP;
|
||||
}
|
||||
|
||||
private boolean detectBothTouch(){
|
||||
return detectionMethod == DETECTION_METHOD_BOTH;
|
||||
return mDetectionMethod == DETECTION_METHOD_BOTH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public final class Tools {
|
||||
versionName = versionInfo.inheritsFrom;
|
||||
}
|
||||
|
||||
String userType = "mojang";
|
||||
String userType = "msa";
|
||||
|
||||
File gameDir = new File(strGameDir);
|
||||
gameDir.mkdirs();
|
||||
@@ -449,42 +449,37 @@ public final class Tools {
|
||||
private static void showError(final Context ctx, final int titleId, final Throwable e, final boolean exitIfOk, final boolean showMore) {
|
||||
e.printStackTrace();
|
||||
|
||||
Runnable runnable = new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final String errMsg = showMore ? Log.getStackTraceString(e): e.getMessage();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder((Context) ctx)
|
||||
.setTitle(titleId)
|
||||
.setMessage(errMsg)
|
||||
.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();
|
||||
}
|
||||
Runnable runnable = () -> {
|
||||
final String errMsg = showMore ? Log.getStackTraceString(e): e.getMessage();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder((Context) ctx)
|
||||
.setTitle(titleId)
|
||||
.setMessage(errMsg)
|
||||
.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, (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(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();
|
||||
}
|
||||
})
|
||||
.setCancelable(!exitIfOk);
|
||||
try {
|
||||
builder.show();
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setCancelable(!exitIfOk);
|
||||
try {
|
||||
builder.show();
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -495,8 +490,8 @@ public final class Tools {
|
||||
}
|
||||
}
|
||||
|
||||
public static void dialogOnUiThread(final Activity ctx, final CharSequence title, final CharSequence message) {
|
||||
ctx.runOnUiThread(() -> new AlertDialog.Builder(ctx)
|
||||
public static void dialogOnUiThread(final Activity activity, final CharSequence title, final CharSequence message) {
|
||||
activity.runOnUiThread(() -> new AlertDialog.Builder(activity)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
@@ -568,7 +563,7 @@ public final class Tools {
|
||||
}catch(IOException e) {
|
||||
throw new RuntimeException("Can't find the source version for "+ versionName +" (req version="+customVer.inheritsFrom+")");
|
||||
}
|
||||
inheritsVer.inheritsFrom = inheritsVer.id;
|
||||
//inheritsVer.inheritsFrom = inheritsVer.id;
|
||||
insertSafety(inheritsVer, customVer,
|
||||
"assetIndex", "assets", "id",
|
||||
"mainClass", "minecraftArguments",
|
||||
@@ -664,23 +659,19 @@ public final class Tools {
|
||||
}
|
||||
|
||||
public static String convertStream(InputStream inputStream, Charset charset) throws IOException {
|
||||
String out = "";
|
||||
StringBuilder out = new StringBuilder();
|
||||
int len;
|
||||
byte[] buf = new byte[512];
|
||||
while((len = inputStream.read(buf))!=-1) {
|
||||
out += new String(buf,0,len,charset);
|
||||
out.append(new String(buf, 0, len, charset));
|
||||
}
|
||||
return out;
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static File lastFileModified(String dir) {
|
||||
File fl = new File(dir);
|
||||
|
||||
File[] files = fl.listFiles(new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.isFile();
|
||||
}
|
||||
});
|
||||
File[] files = fl.listFiles(File::isFile);
|
||||
|
||||
long lastMod = Long.MIN_VALUE;
|
||||
File choice = null;
|
||||
@@ -696,13 +687,13 @@ public final class Tools {
|
||||
|
||||
|
||||
public static String read(InputStream is) throws IOException {
|
||||
String out = "";
|
||||
StringBuilder out = new StringBuilder();
|
||||
int len;
|
||||
byte[] buf = new byte[512];
|
||||
while((len = is.read(buf))!=-1) {
|
||||
out += new String(buf,0,len);
|
||||
out.append(new String(buf, 0, len));
|
||||
}
|
||||
return out;
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static String read(String path) throws IOException {
|
||||
@@ -748,6 +739,7 @@ public final class Tools {
|
||||
public abstract static class DownloaderFeedback {
|
||||
public abstract void updateProgress(int curr, int max);
|
||||
}
|
||||
|
||||
public static void downloadFileMonitored(String urlInput,String nameOutput, DownloaderFeedback monitor) throws IOException {
|
||||
File nameOutputFile = new File(nameOutput);
|
||||
if (!nameOutputFile.exists()) {
|
||||
@@ -784,75 +776,6 @@ public final class Tools {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public static class ZipTool
|
||||
{
|
||||
private ZipTool(){}
|
||||
public static void zip(List<File> files, File zipFile) throws IOException {
|
||||
final int BUFFER_SIZE = 2048;
|
||||
|
||||
BufferedInputStream origin = null;
|
||||
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
|
||||
|
||||
try {
|
||||
byte data[] = new byte[BUFFER_SIZE];
|
||||
|
||||
for (File file : files) {
|
||||
FileInputStream fileInputStream = new FileInputStream( file );
|
||||
|
||||
origin = new BufferedInputStream(fileInputStream, BUFFER_SIZE);
|
||||
|
||||
try {
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
|
||||
out.putNextEntry(entry);
|
||||
|
||||
int count;
|
||||
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
origin.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
public static void unzip(File zipFile, File targetDirectory) throws IOException {
|
||||
final int BUFFER_SIZE = 1024;
|
||||
ZipInputStream zis = new ZipInputStream(
|
||||
new BufferedInputStream(new FileInputStream(zipFile)));
|
||||
try {
|
||||
ZipEntry ze;
|
||||
int count;
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
File file = new File(targetDirectory, ze.getName());
|
||||
File dir = ze.isDirectory() ? file : file.getParentFile();
|
||||
if (!dir.isDirectory() && !dir.mkdirs())
|
||||
throw new FileNotFoundException("Failed to ensure directory: " +
|
||||
dir.getAbsolutePath());
|
||||
if (ze.isDirectory())
|
||||
continue;
|
||||
FileOutputStream fout = new FileOutputStream(file);
|
||||
try {
|
||||
while ((count = zis.read(buffer)) != -1)
|
||||
fout.write(buffer, 0, count);
|
||||
} finally {
|
||||
fout.close();
|
||||
}
|
||||
/* if time should be restored as well
|
||||
long time = ze.getTime();
|
||||
if (time > 0)
|
||||
file.setLastModified(time);
|
||||
*/
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ignoreNotch(boolean shouldIgnore, Activity ctx){
|
||||
if (SDK_INT >= P) {
|
||||
|
||||
@@ -27,19 +27,19 @@ import org.lwjgl.glfw.CallbackBridge;
|
||||
*/
|
||||
public class Touchpad extends FrameLayout {
|
||||
/* Whether the Touchpad should be displayed */
|
||||
private boolean displayState;
|
||||
private boolean mDisplayState;
|
||||
/* Mouse pointer icon used by the touchpad */
|
||||
private final ImageView mousePointer = new ImageView(getContext());
|
||||
private final ImageView mMousePointerImageView = new ImageView(getContext());
|
||||
/* Detect a classic android Tap */
|
||||
private final GestureDetector singleTapDetector = new GestureDetector(getContext(), new SingleTapConfirm());
|
||||
private final GestureDetector mSingleTapDetector = new GestureDetector(getContext(), new SingleTapConfirm());
|
||||
/* Resolution scaler option, allow downsizing a window */
|
||||
private final float scaleFactor = DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
private final float mScaleFactor = DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
/* Current pointer ID to move the mouse */
|
||||
private int currentPointerID = -1000;
|
||||
private int mCurrentPointerID = -1000;
|
||||
/* Previous MotionEvent position, not scale */
|
||||
private float prevX, prevY;
|
||||
private float mPrevX, mPrevY;
|
||||
/* Last first pointer positions non-scaled, used to scroll distance */
|
||||
private float scrollLastInitialX, scrollLastInitialY;
|
||||
private float mScrollLastInitialX, mScrollLastInitialY;
|
||||
|
||||
public Touchpad(@NonNull Context context) {
|
||||
this(context, null);
|
||||
@@ -50,56 +50,6 @@ public class Touchpad extends FrameLayout {
|
||||
init();
|
||||
}
|
||||
|
||||
private void init(){
|
||||
// Setup mouse pointer
|
||||
mousePointer.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.mouse_pointer, getContext().getTheme()));
|
||||
mousePointer.post(() -> {
|
||||
ViewGroup.LayoutParams params = mousePointer.getLayoutParams();
|
||||
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
});
|
||||
addView(mousePointer);
|
||||
setFocusable(false);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
setDefaultFocusHighlightEnabled(false);
|
||||
}
|
||||
|
||||
// When the game is grabbing, we should not display the mouse
|
||||
disable();
|
||||
displayState = false;
|
||||
Thread virtualMouseGrabThread = new Thread(() -> {
|
||||
while (true) {
|
||||
if (!CallbackBridge.isGrabbing() && displayState && getVisibility() != VISIBLE) {
|
||||
post(this::enable);
|
||||
}else{
|
||||
if ((CallbackBridge.isGrabbing() && getVisibility() != View.GONE) || !displayState && getVisibility() == VISIBLE) {
|
||||
post(this::disable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}, "VirtualMouseGrabThread");
|
||||
virtualMouseGrabThread.setPriority(Thread.MIN_PRIORITY);
|
||||
virtualMouseGrabThread.start();
|
||||
}
|
||||
|
||||
/** Enable the touchpad */
|
||||
public void enable(){
|
||||
setVisibility(VISIBLE);
|
||||
placeMouseAt(currentDisplayMetrics.widthPixels / 2, currentDisplayMetrics.heightPixels / 2);
|
||||
}
|
||||
|
||||
/** Disable the touchpad and hides the mouse */
|
||||
public void disable(){
|
||||
setVisibility(GONE);
|
||||
}
|
||||
|
||||
/** @return The new state, enabled or disabled */
|
||||
public boolean switchState(){
|
||||
displayState = !displayState;
|
||||
return displayState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// MotionEvent reports input details from the touch screen
|
||||
@@ -114,77 +64,126 @@ public class Touchpad extends FrameLayout {
|
||||
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
float mouseX = mousePointer.getX();
|
||||
float mouseY = mousePointer.getY();
|
||||
float mouseX = mMousePointerImageView.getX();
|
||||
float mouseY = mMousePointerImageView.getY();
|
||||
|
||||
if (singleTapDetector.onTouchEvent(event)) {
|
||||
CallbackBridge.mouseX = (mouseX * scaleFactor);
|
||||
CallbackBridge.mouseY = (mouseY * scaleFactor);
|
||||
if (mSingleTapDetector.onTouchEvent(event)) {
|
||||
CallbackBridge.mouseX = (mouseX * mScaleFactor);
|
||||
CallbackBridge.mouseY = (mouseY * mScaleFactor);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT);
|
||||
CallbackBridge.sendMouseKeycode(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
scrollLastInitialX = event.getX();
|
||||
scrollLastInitialY = event.getY();
|
||||
mScrollLastInitialX = event.getX();
|
||||
mScrollLastInitialY = event.getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
currentPointerID = event.getPointerId(0);
|
||||
mPrevX = x;
|
||||
mPrevY = y;
|
||||
mCurrentPointerID = event.getPointerId(0);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
//Scrolling feature
|
||||
if (!LauncherPreferences.PREF_DISABLE_GESTURES && !CallbackBridge.isGrabbing() && event.getPointerCount() >= 2) {
|
||||
int hScroll = ((int) (event.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
|
||||
int vScroll = ((int) (event.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
|
||||
int hScroll = ((int) (event.getX() - mScrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
|
||||
int vScroll = ((int) (event.getY() - mScrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
|
||||
|
||||
if(vScroll != 0 || hScroll != 0){
|
||||
CallbackBridge.sendScroll(hScroll, vScroll);
|
||||
scrollLastInitialX = event.getX();
|
||||
scrollLastInitialY = event.getY();
|
||||
mScrollLastInitialX = event.getX();
|
||||
mScrollLastInitialY = event.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Mouse movement
|
||||
if(currentPointerID == event.getPointerId(0)) {
|
||||
mouseX = Math.max(0, Math.min(currentDisplayMetrics.widthPixels, mouseX + (x - prevX) * LauncherPreferences.PREF_MOUSESPEED));
|
||||
mouseY = Math.max(0, Math.min(currentDisplayMetrics.heightPixels, mouseY + (y - prevY) * LauncherPreferences.PREF_MOUSESPEED));
|
||||
if(mCurrentPointerID == event.getPointerId(0)) {
|
||||
mouseX = Math.max(0, Math.min(currentDisplayMetrics.widthPixels, mouseX + (x - mPrevX) * LauncherPreferences.PREF_MOUSESPEED));
|
||||
mouseY = Math.max(0, Math.min(currentDisplayMetrics.heightPixels, mouseY + (y - mPrevY) * LauncherPreferences.PREF_MOUSESPEED));
|
||||
|
||||
placeMouseAt(mouseX, mouseY);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
}else currentPointerID = event.getPointerId(0);
|
||||
}else mCurrentPointerID = event.getPointerId(0);
|
||||
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
mPrevX = x;
|
||||
mPrevY = y;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
currentPointerID = -1000;
|
||||
mPrevX = x;
|
||||
mPrevY = y;
|
||||
mCurrentPointerID = -1000;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
|
||||
CallbackBridge.DEBUG_STRING.setLength(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Enable the touchpad */
|
||||
public void enable(){
|
||||
setVisibility(VISIBLE);
|
||||
placeMouseAt(currentDisplayMetrics.widthPixels / 2, currentDisplayMetrics.heightPixels / 2);
|
||||
}
|
||||
|
||||
/** Disable the touchpad and hides the mouse */
|
||||
public void disable(){
|
||||
setVisibility(GONE);
|
||||
}
|
||||
|
||||
/** @return The new state, enabled or disabled */
|
||||
public boolean switchState(){
|
||||
mDisplayState = !mDisplayState;
|
||||
return mDisplayState;
|
||||
}
|
||||
|
||||
public void placeMouseAt(float x, float y) {
|
||||
mousePointer.setX(x);
|
||||
mousePointer.setY(y);
|
||||
CallbackBridge.mouseX = (x * scaleFactor);
|
||||
CallbackBridge.mouseY = (y * scaleFactor);
|
||||
mMousePointerImageView.setX(x);
|
||||
mMousePointerImageView.setY(y);
|
||||
CallbackBridge.mouseX = (x * mScaleFactor);
|
||||
CallbackBridge.mouseY = (y * mScaleFactor);
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
}
|
||||
|
||||
private void init(){
|
||||
// Setup mouse pointer
|
||||
mMousePointerImageView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_mouse_pointer, getContext().getTheme()));
|
||||
mMousePointerImageView.post(() -> {
|
||||
ViewGroup.LayoutParams params = mMousePointerImageView.getLayoutParams();
|
||||
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
|
||||
});
|
||||
addView(mMousePointerImageView);
|
||||
setFocusable(false);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
setDefaultFocusHighlightEnabled(false);
|
||||
}
|
||||
|
||||
// When the game is grabbing, we should not display the mouse
|
||||
disable();
|
||||
mDisplayState = false;
|
||||
Thread virtualMouseGrabThread = new Thread(() -> {
|
||||
while (true) {
|
||||
if (!CallbackBridge.isGrabbing() && mDisplayState && getVisibility() != VISIBLE) {
|
||||
post(this::enable);
|
||||
}else{
|
||||
if ((CallbackBridge.isGrabbing() && getVisibility() != View.GONE) || !mDisplayState && getVisibility() == VISIBLE) {
|
||||
post(this::disable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}, "VirtualMouseGrabThread");
|
||||
virtualMouseGrabThread.setPriority(Thread.MIN_PRIORITY);
|
||||
virtualMouseGrabThread.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
@@ -24,6 +25,7 @@ public class MicrosoftLoginGUIActivity extends AppCompatActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
waitDialog = new ProgressDialog(this);
|
||||
waitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
waitDialog.setIndeterminate(true);
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
public interface LoginListener
|
||||
{
|
||||
public void onBeforeLogin();
|
||||
public void onLoginDone(String[] result);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
import android.os.*;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class LoginTask extends AsyncTask<String, Void, Void>
|
||||
{
|
||||
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
|
||||
//private String TAG = "MojangAuth-login";
|
||||
private LoginListener listener;
|
||||
|
||||
public LoginTask setLoginListener(LoginListener listener) {
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
private UUID getRandomUUID() {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
listener.onBeforeLogin();
|
||||
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(String[] args) {
|
||||
ArrayList<String> str = new ArrayList<String>();
|
||||
str.add("ERROR");
|
||||
try{
|
||||
try{
|
||||
AuthenticateResponse response = authenticator.authenticate(args[0], args[1], getRandomUUID());
|
||||
if (response.selectedProfile == null) {
|
||||
str.add("Can't login a demo account!\n");
|
||||
} else {
|
||||
if (new File(Tools.DIR_ACCOUNT_NEW + "/" + response.selectedProfile.name + ".json").exists()) {
|
||||
str.add("This account already exist!\n");
|
||||
} else {
|
||||
str.add(response.accessToken); // Access token
|
||||
str.add(response.clientToken.toString()); // Client token
|
||||
str.add(response.selectedProfile.id); // Profile ID
|
||||
str.add(response.selectedProfile.name); // Username
|
||||
str.set(0, "NORMAL");
|
||||
}
|
||||
}
|
||||
}
|
||||
//MainActivity.updateStatus(804);
|
||||
catch(Throwable e){
|
||||
str.add(e.getMessage());
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
str.add(e.getMessage());
|
||||
}
|
||||
|
||||
listener.onLoginDone(str.toArray(new String[0]));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// listener.onLoginDone(result);
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
|
||||
import android.app.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
|
||||
public class RefreshTokenTask extends AsyncTask<String, Void, Throwable> {
|
||||
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
|
||||
//private Gson gson = new Gson();
|
||||
private RefreshListener listener;
|
||||
private MinecraftAccount profilePath;
|
||||
|
||||
private final WeakReference<Context> ctx;
|
||||
private ProgressDialog build;
|
||||
|
||||
public RefreshTokenTask(Context ctx, RefreshListener listener) {
|
||||
this.ctx = new WeakReference<>(ctx);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreExecute() {
|
||||
build = new ProgressDialog(ctx.get());
|
||||
build.setMessage(ctx.get().getString(R.string.global_waiting));
|
||||
build.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
build.setCancelable(false);
|
||||
build.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable doInBackground(String... args) {
|
||||
try {
|
||||
this.profilePath = MinecraftAccount.load(args[0]);
|
||||
int responseCode = 400;
|
||||
try {
|
||||
responseCode = this.authenticator.validate(profilePath.accessToken).statusCode;
|
||||
}catch(RuntimeException e) {}
|
||||
|
||||
if (responseCode == 403) {
|
||||
RefreshResponse response = this.authenticator.refresh(profilePath.accessToken, UUID.fromString(profilePath.clientToken));
|
||||
if (response == null) {
|
||||
// Refresh when offline?
|
||||
return null;
|
||||
} else if (response.selectedProfile == null) {
|
||||
throw new IllegalArgumentException("Can't refresh a demo account!");
|
||||
}
|
||||
|
||||
profilePath.clientToken = response.clientToken.toString();
|
||||
profilePath.accessToken = response.accessToken;
|
||||
profilePath.username = response.selectedProfile.name;
|
||||
profilePath.profileId = response.selectedProfile.id;
|
||||
}
|
||||
profilePath.updateSkinFace();
|
||||
profilePath.save();
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(Throwable result) {
|
||||
build.dismiss();
|
||||
if (result == null) {
|
||||
listener.onSuccess(profilePath);
|
||||
} else {
|
||||
listener.onFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthenticateRequest {
|
||||
public AgentInfo agent = new AgentInfo();
|
||||
public UUID clientToken;
|
||||
public String password;
|
||||
public String username;
|
||||
|
||||
public static class AgentInfo {
|
||||
public String name;
|
||||
public int version;
|
||||
}
|
||||
|
||||
public AuthenticateRequest(String username, String password, UUID clientToken, String clientName, int clientVersion) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.clientToken = clientToken;
|
||||
this.agent.name = clientName;
|
||||
this.agent.version = clientVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthenticateResponse {
|
||||
public String accessToken;
|
||||
public Profile[] availableProfiles;
|
||||
public UUID clientToken;
|
||||
public Profile selectedProfile;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class RefreshResponse {
|
||||
public String accessToken;
|
||||
public UUID clientToken;
|
||||
public Profile selectedProfile;
|
||||
}
|
||||
|
||||
@@ -90,31 +90,6 @@ public class YggdrasilAuthenticator {
|
||||
}
|
||||
}
|
||||
|
||||
public AuthenticateResponse authenticate(String username, String password, UUID clientId) throws IOException, Throwable {
|
||||
NetworkResponse obj = makeRequest("authenticate", new AuthenticateRequest(username, password, clientId, this.clientName, this.clientVersion), AuthenticateResponse.class);
|
||||
/*
|
||||
if (obj.statusCode != 200) {
|
||||
throw new RuntimeException("Invalid username or password, status code: " + obj.statusCode);
|
||||
}
|
||||
*/
|
||||
obj.throwExceptionIfNeed();
|
||||
return (AuthenticateResponse) obj.response;
|
||||
}
|
||||
|
||||
public RefreshResponse refresh(String authToken, UUID clientId) throws IOException, Throwable {
|
||||
NetworkResponse obj = makeRequest("refresh", new RefreshRequest(authToken, clientId), RefreshResponse.class);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
} else {
|
||||
obj.throwExceptionIfNeed(); // "Invalid username or password, status code: " + obj.statusCode);
|
||||
return (RefreshResponse) obj.response;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkResponse validate(String authToken) throws Throwable {
|
||||
return makeRequest("validate", new RefreshRequest(authToken, null), null);
|
||||
}
|
||||
|
||||
public NetworkResponse invalidate(String authToken, UUID clientId) throws Throwable {
|
||||
return makeRequest("invalidate", new RefreshRequest(authToken, clientId), null);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,11 @@ import net.objecthunter.exp4j.function.Function;
|
||||
|
||||
import org.lwjgl.glfw.*;
|
||||
|
||||
import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN;
|
||||
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
@Keep
|
||||
public class ControlData {
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.HandleView;
|
||||
import net.kdt.pojavlaunch.prefs.*;
|
||||
|
||||
public class ControlLayout extends FrameLayout
|
||||
{
|
||||
public class ControlLayout extends FrameLayout {
|
||||
protected CustomControls mLayout;
|
||||
private boolean mModifiable;
|
||||
private CustomControlsActivity mActivity;
|
||||
|
||||
@@ -3,12 +3,9 @@ import android.content.*;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import org.lwjgl.glfw.*;
|
||||
|
||||
@Keep
|
||||
public class CustomControls {
|
||||
@@ -37,22 +34,22 @@ public class CustomControls {
|
||||
this.mControlDataList.add(new ControlData(ControlData.getSpecialButtons()[3])); // Secondary Mouse mControlDataList
|
||||
this.mControlDataList.add(new ControlData(ControlData.getSpecialButtons()[4])); // Virtual mouse toggle
|
||||
|
||||
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_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, 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_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, new int[]{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, new int[]{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, new int[]{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 = 4;
|
||||
@@ -60,7 +57,7 @@ public class CustomControls {
|
||||
|
||||
|
||||
public void save(String path) throws IOException {
|
||||
//Current version is the V2.4 so the version as to be marked as 4 !
|
||||
//Current version is the V2.5 so the version as to be marked as 4 !
|
||||
version = 4;
|
||||
|
||||
Tools.write(path, Tools.GLOBAL_GSON.toJson(this));
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.kdt.pojavlaunch.customcontrols;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
|
||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@@ -83,10 +83,10 @@ public class LayoutConverter {
|
||||
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};
|
||||
int[] keycodes = new int[] {LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
|
||||
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
|
||||
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
|
||||
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN};
|
||||
n_button.isDynamicBtn = button.getBoolean("isDynamicBtn");
|
||||
n_button.dynamicX = button.getString("dynamicX");
|
||||
n_button.dynamicY = button.getString("dynamicY");
|
||||
@@ -116,9 +116,9 @@ public class LayoutConverter {
|
||||
}
|
||||
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++; }
|
||||
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;
|
||||
empty.mControlDataList.add(n_button);
|
||||
|
||||
@@ -11,13 +11,11 @@ import android.content.res.Configuration;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.kdt.pojavlaunch.BaseMainActivity;
|
||||
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
|
||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
@@ -38,7 +36,7 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
|
||||
}
|
||||
|
||||
|
||||
private boolean isDoingInternalChanges = false;
|
||||
private boolean mIsDoingInternalChanges = false;
|
||||
|
||||
/**
|
||||
* We take the new chars, and send them to the game.
|
||||
@@ -48,10 +46,10 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
|
||||
@Override
|
||||
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
|
||||
super.onTextChanged(text, start, lengthBefore, lengthAfter);
|
||||
if(isDoingInternalChanges)return;
|
||||
if(mIsDoingInternalChanges)return;
|
||||
|
||||
for(int i=0; i< lengthBefore; ++i){
|
||||
CallbackBridge.sendKeycode(LWJGLGLFWKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
|
||||
for(int i=0; i < lengthBefore; ++i){
|
||||
CallbackBridge.sendKeycode(LwjglGlfwKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
|
||||
}
|
||||
for(int i=start, count = 0; count < lengthAfter; ++i){
|
||||
CallbackBridge.sendChar(text.charAt(i), 0);
|
||||
@@ -115,20 +113,12 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
|
||||
*/
|
||||
@SuppressLint("SetTextI18n")
|
||||
public void clear(){
|
||||
isDoingInternalChanges = true;
|
||||
mIsDoingInternalChanges = true;
|
||||
//Braille space, doesn't trigger keyboard auto-complete
|
||||
//replacing directly the text without though setText avoids notifying changes
|
||||
setText(" ");
|
||||
setSelection(getText().length());
|
||||
isDoingInternalChanges = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the enter key.
|
||||
*/
|
||||
private void sendEnter(){
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ENTER);
|
||||
clear();
|
||||
mIsDoingInternalChanges = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,6 +142,13 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the enter key.
|
||||
*/
|
||||
private void sendEnter(){
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ENTER);
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function deals with anything that has to be executed when the constructor is called
|
||||
|
||||
@@ -16,11 +16,10 @@ 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;
|
||||
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_BOTTOM_OFFSET;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_LEFT_OFFSET;
|
||||
@@ -30,19 +29,15 @@ import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener
|
||||
{
|
||||
private final Paint mRectPaint = new Paint();;
|
||||
|
||||
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener {
|
||||
private final Paint mRectPaint = new Paint();
|
||||
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;
|
||||
protected boolean mIsToggled = false;
|
||||
protected boolean mIsPointerOutOfBounds = false;
|
||||
|
||||
public ControlButton(ControlLayout layout, ControlData properties) {
|
||||
super(layout.getContext());
|
||||
@@ -259,7 +254,7 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (isToggled || (!mProperties.isToggle && isActivated()))
|
||||
if (mIsToggled || (!mProperties.isToggle && isActivated()))
|
||||
canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mProperties.cornerRadius, mProperties.cornerRadius, mRectPaint);
|
||||
}
|
||||
|
||||
@@ -304,26 +299,26 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
||||
//If out of bounds
|
||||
if(event.getX() < getLeft() || event.getX() > getRight() ||
|
||||
event.getY() < getTop() || event.getY() > getBottom()){
|
||||
if(mProperties.isSwipeable && !isPointerOutOfBounds){
|
||||
if(mProperties.isSwipeable && !mIsPointerOutOfBounds){
|
||||
//Remove keys
|
||||
if(!triggerToggle()) {
|
||||
sendKeyPresses(false);
|
||||
}
|
||||
}
|
||||
isPointerOutOfBounds = true;
|
||||
mIsPointerOutOfBounds = true;
|
||||
((ControlLayout) getParent()).onTouch(this, event);
|
||||
break;
|
||||
}
|
||||
|
||||
//Else if we now are in bounds
|
||||
if(isPointerOutOfBounds) {
|
||||
if(mIsPointerOutOfBounds) {
|
||||
((ControlLayout) getParent()).onTouch(this, event);
|
||||
//RE-press the button
|
||||
if(mProperties.isSwipeable && !mProperties.isToggle){
|
||||
sendKeyPresses(true);
|
||||
}
|
||||
}
|
||||
isPointerOutOfBounds = false;
|
||||
mIsPointerOutOfBounds = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN: // 0
|
||||
@@ -340,8 +335,8 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
||||
MinecraftGLView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
|
||||
if (v != null) v.dispatchTouchEvent(event);
|
||||
}
|
||||
if(isPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);
|
||||
isPointerOutOfBounds = false;
|
||||
if(mIsPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);
|
||||
mIsPointerOutOfBounds = false;
|
||||
|
||||
if(!triggerToggle()) {
|
||||
sendKeyPresses(false);
|
||||
@@ -501,9 +496,9 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
||||
public boolean triggerToggle(){
|
||||
//returns true a the toggle system is triggered
|
||||
if(mProperties.isToggle){
|
||||
isToggled = !isToggled;
|
||||
mIsToggled = !mIsToggled;
|
||||
invalidate();
|
||||
sendKeyPresses(isToggled);
|
||||
sendKeyPresses(mIsToggled);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -536,15 +531,15 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
||||
break;
|
||||
|
||||
case ControlData.SPECIALBTN_MOUSEPRI:
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
|
||||
break;
|
||||
|
||||
case ControlData.SPECIALBTN_MOUSEMID:
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown);
|
||||
break;
|
||||
|
||||
case ControlData.SPECIALBTN_MOUSESEC:
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
|
||||
break;
|
||||
|
||||
case ControlData.SPECIALBTN_SCROLLDOWN:
|
||||
|
||||
@@ -2,7 +2,6 @@ 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;
|
||||
@@ -20,7 +19,7 @@ public class ControlDrawer extends ControlButton {
|
||||
|
||||
public ArrayList<ControlSubButton> buttons;
|
||||
public ControlDrawerData drawerData;
|
||||
public ControlLayout mLayout;
|
||||
public ControlLayout layout;
|
||||
public boolean areButtonsVisible;
|
||||
|
||||
|
||||
@@ -28,14 +27,14 @@ public class ControlDrawer extends ControlButton {
|
||||
super(layout, drawerData.properties);
|
||||
|
||||
buttons = new ArrayList<>(drawerData.buttonProperties.size());
|
||||
mLayout = layout;
|
||||
this.layout = layout;
|
||||
this.drawerData = drawerData;
|
||||
areButtonsVisible = layout.getModifiable();
|
||||
}
|
||||
|
||||
|
||||
public void addButton(ControlData properties){
|
||||
addButton(new ControlSubButton(mLayout, properties, this));
|
||||
addButton(new ControlSubButton(layout, properties, this));
|
||||
}
|
||||
|
||||
public void addButton(ControlSubButton button){
|
||||
|
||||
@@ -15,7 +15,7 @@ import android.widget.Toast;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.core.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
|
||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
import net.kdt.pojavlaunch.utils.MCOptionUtils;
|
||||
@@ -40,60 +40,60 @@ import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||
public class Gamepad {
|
||||
|
||||
/* Resolution scaler option, allow downsizing a window */
|
||||
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||
/* Mouse positions, scaled by the scaleFactor */
|
||||
private float mouse_x, mouse_y;
|
||||
private float mMouse_x, mMouse_y;
|
||||
/* Sensitivity, adjusted according to screen size */
|
||||
private final double sensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
|
||||
private final double mSensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
|
||||
|
||||
private final ImageView pointerView;
|
||||
private final ImageView mPointerImageView;
|
||||
|
||||
private final GamepadDpad gamepadDpad = new GamepadDpad();
|
||||
private final GamepadDpad mGamepadDpad = new GamepadDpad();
|
||||
|
||||
private final GamepadJoystick leftJoystick;
|
||||
private int currentJoystickDirection = DIRECTION_NONE;
|
||||
private final GamepadJoystick mLeftJoystick;
|
||||
private int mCurrentJoystickDirection = DIRECTION_NONE;
|
||||
|
||||
private final GamepadJoystick rightJoystick;
|
||||
private float lastHorizontalValue = 0.0f;
|
||||
private float lastVerticalValue = 0.0f;
|
||||
private final GamepadJoystick mRightJoystick;
|
||||
private float mLastHorizontalValue = 0.0f;
|
||||
private float mLastVerticalValue = 0.0f;
|
||||
|
||||
private final double mouseMaxAcceleration = 2f;
|
||||
private final double MOUSE_MAX_ACCELERATION = 2f;
|
||||
|
||||
private double mouseMagnitude;
|
||||
private double mouseAngle;
|
||||
private double mouseSensitivity = 19;
|
||||
private double mMouseMagnitude;
|
||||
private double mMouseAngle;
|
||||
private double mMouseSensitivity = 19;
|
||||
|
||||
private final GamepadMap gameMap = GamepadMap.getDefaultGameMap();
|
||||
private final GamepadMap menuMap = GamepadMap.getDefaultMenuMap();
|
||||
private GamepadMap currentMap = gameMap;
|
||||
private final GamepadMap mGameMap = GamepadMap.getDefaultGameMap();
|
||||
private final GamepadMap mMenuMap = GamepadMap.getDefaultMenuMap();
|
||||
private GamepadMap mCurrentMap = mGameMap;
|
||||
|
||||
private boolean lastGrabbingState = true;
|
||||
private boolean mLastGrabbingState = true;
|
||||
//private final boolean mModifierDigitalTriggers;
|
||||
private final boolean mModifierAnalogTriggers;
|
||||
private boolean mModifierSwappedAxis = true; //Triggers and right stick axis are swapped.
|
||||
|
||||
/* Choreographer with time to compute delta on ticking */
|
||||
private final Choreographer screenChoreographer;
|
||||
private long lastFrameTime;
|
||||
private final Choreographer mScreenChoreographer;
|
||||
private long mLastFrameTime;
|
||||
|
||||
/* Listen for change in gui scale */
|
||||
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> notifyGUISizeChange(getMcScale());
|
||||
private MCOptionUtils.MCOptionListener mGuiScaleListener = () -> notifyGUISizeChange(getMcScale());
|
||||
|
||||
public Gamepad(View contextView, InputDevice inputDevice){
|
||||
screenChoreographer = Choreographer.getInstance();
|
||||
mScreenChoreographer = Choreographer.getInstance();
|
||||
Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
|
||||
@Override
|
||||
public void doFrame(long frameTimeNanos) {
|
||||
updateGrabbingState();
|
||||
tick(frameTimeNanos);
|
||||
screenChoreographer.postFrameCallback(this);
|
||||
mScreenChoreographer.postFrameCallback(this);
|
||||
}
|
||||
};
|
||||
screenChoreographer.postFrameCallback(frameCallback);
|
||||
lastFrameTime = System.nanoTime();
|
||||
mScreenChoreographer.postFrameCallback(frameCallback);
|
||||
mLastFrameTime = System.nanoTime();
|
||||
|
||||
/* Add the listener for the cross hair */
|
||||
MCOptionUtils.addMCOptionListener(GUIScaleListener);
|
||||
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
|
||||
|
||||
Toast.makeText(contextView.getContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show();
|
||||
for(InputDevice.MotionRange range : inputDevice.getMotionRanges()){
|
||||
@@ -106,98 +106,31 @@ public class Gamepad {
|
||||
}
|
||||
}
|
||||
|
||||
leftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
|
||||
mLeftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
|
||||
if(!mModifierSwappedAxis)
|
||||
rightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
|
||||
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
|
||||
else
|
||||
rightJoystick = new GamepadJoystick(MotionEvent.AXIS_RX, MotionEvent.AXIS_RY, inputDevice);
|
||||
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_RX, MotionEvent.AXIS_RY, inputDevice);
|
||||
|
||||
//mModifierDigitalTriggers = inputDevice.hasKeys(KeyEvent.KEYCODE_BUTTON_R2)[0];
|
||||
mModifierAnalogTriggers = supportAnalogTriggers(inputDevice);
|
||||
|
||||
Context ctx = contextView.getContext();
|
||||
pointerView = new ImageView(contextView.getContext());
|
||||
pointerView.setImageDrawable(ResourcesCompat.getDrawable(ctx.getResources(), R.drawable.pointer, ctx.getTheme()));
|
||||
pointerView.getDrawable().setFilterBitmap(false);
|
||||
mPointerImageView = new ImageView(contextView.getContext());
|
||||
mPointerImageView.setImageDrawable(ResourcesCompat.getDrawable(ctx.getResources(), R.drawable.ic_gamepad_pointer, ctx.getTheme()));
|
||||
mPointerImageView.getDrawable().setFilterBitmap(false);
|
||||
|
||||
int size = (int) ((22 * getMcScale()) / scaleFactor);
|
||||
pointerView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
|
||||
int size = (int) ((22 * getMcScale()) / mScaleFactor);
|
||||
mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
|
||||
|
||||
mouse_x = CallbackBridge.windowWidth/2;
|
||||
mouse_y = CallbackBridge.windowHeight/2;
|
||||
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
|
||||
mMouse_x = CallbackBridge.windowWidth/2;
|
||||
mMouse_y = CallbackBridge.windowHeight/2;
|
||||
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
|
||||
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
||||
|
||||
((ViewGroup)contextView.getParent()).addView(pointerView);
|
||||
((ViewGroup)contextView.getParent()).addView(mPointerImageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the new mouse position, computing the delta
|
||||
* @param frameTimeNanos The time to render the frame, used to compute mouse delta
|
||||
*/
|
||||
public void tick(long frameTimeNanos){
|
||||
//update mouse position
|
||||
if(lastHorizontalValue != 0 || lastVerticalValue != 0){
|
||||
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
|
||||
|
||||
double acceleration = (mouseMagnitude - currentJoystick.getDeadzone()) / (1 - currentJoystick.getDeadzone());
|
||||
acceleration = Math.pow(acceleration, mouseMaxAcceleration);
|
||||
if(acceleration > 1) acceleration = 1;
|
||||
|
||||
// Compute delta since last tick time
|
||||
float deltaX = (float) (Math.cos(mouseAngle) * acceleration * mouseSensitivity);
|
||||
float deltaY = (float) (Math.sin(mouseAngle) * acceleration * mouseSensitivity);
|
||||
float deltaTimeScale = ((frameTimeNanos - lastFrameTime) / 16666666f); // Scale of 1 = 60Hz
|
||||
deltaX *= deltaTimeScale;
|
||||
deltaY *= deltaTimeScale;
|
||||
|
||||
CallbackBridge.mouseX += deltaX;
|
||||
CallbackBridge.mouseY -= deltaY;
|
||||
|
||||
if(!lastGrabbingState){
|
||||
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
|
||||
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
|
||||
placePointerView((int) (CallbackBridge.mouseX / scaleFactor), (int) (CallbackBridge.mouseY/ scaleFactor));
|
||||
}
|
||||
|
||||
mouse_x = CallbackBridge.mouseX;
|
||||
mouse_y = CallbackBridge.mouseY;
|
||||
|
||||
//Send the mouse to the game
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
}
|
||||
|
||||
// Update last nano time
|
||||
lastFrameTime = frameTimeNanos;
|
||||
}
|
||||
|
||||
/** Update the grabbing state, and change the currentMap, mouse position and sensibility */
|
||||
private void updateGrabbingState() {
|
||||
boolean lastGrabbingValue = lastGrabbingState;
|
||||
lastGrabbingState = CallbackBridge.isGrabbing();
|
||||
if(lastGrabbingValue == lastGrabbingState) return;
|
||||
|
||||
// Switch grabbing state then
|
||||
currentMap.resetPressedState();
|
||||
if(lastGrabbingState){
|
||||
currentMap = gameMap;
|
||||
pointerView.setVisibility(View.INVISIBLE);
|
||||
mouseSensitivity = 18;
|
||||
return;
|
||||
}
|
||||
|
||||
currentMap = menuMap;
|
||||
sendDirectionalKeycode(currentJoystickDirection, false, gameMap); // removing what we were doing
|
||||
|
||||
mouse_x = CallbackBridge.windowWidth/2;
|
||||
mouse_y = CallbackBridge.windowHeight/2;
|
||||
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
|
||||
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
||||
pointerView.setVisibility(View.VISIBLE);
|
||||
// Sensitivity in menu is MC and HARDWARE resolution dependent
|
||||
mouseSensitivity = 19 * scaleFactor / sensitivityFactor;
|
||||
|
||||
}
|
||||
|
||||
public void update(KeyEvent event){
|
||||
sendButton(event);
|
||||
@@ -208,125 +141,17 @@ public class Gamepad {
|
||||
updateMouseJoystick(event);
|
||||
updateAnalogTriggers(event);
|
||||
|
||||
int[] dpadEvent = gamepadDpad.convertEvent(event);
|
||||
int[] dpadEvent = mGamepadDpad.convertEvent(event);
|
||||
sendButton(dpadEvent[0], dpadEvent[1]);
|
||||
}
|
||||
|
||||
private void updateMouseJoystick(MotionEvent event){
|
||||
GamepadJoystick currentJoystick = lastGrabbingState ? rightJoystick : leftJoystick;
|
||||
float horizontalValue = currentJoystick.getHorizontalAxis(event);
|
||||
float verticalValue = currentJoystick.getVerticalAxis(event);
|
||||
if(horizontalValue != lastHorizontalValue || verticalValue != lastVerticalValue){
|
||||
lastHorizontalValue = horizontalValue;
|
||||
lastVerticalValue = verticalValue;
|
||||
|
||||
mouseMagnitude = currentJoystick.getMagnitude(event);
|
||||
mouseAngle = currentJoystick.getAngleRadian(event);
|
||||
|
||||
tick(System.nanoTime());
|
||||
return;
|
||||
}
|
||||
lastHorizontalValue = horizontalValue;
|
||||
lastVerticalValue = verticalValue;
|
||||
|
||||
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) return;
|
||||
|
||||
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
|
||||
sendDirectionalKeycode(currentJoystickDirection, true, getCurrentMap());
|
||||
}
|
||||
|
||||
private void updateAnalogTriggers(MotionEvent event){
|
||||
if(mModifierAnalogTriggers){
|
||||
getCurrentMap().TRIGGER_LEFT.update(
|
||||
(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5)
|
||||
|| (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)
|
||||
|| (mModifierSwappedAxis &&(event.getAxisValue(MotionEvent.AXIS_Z) > 0.5)) );
|
||||
getCurrentMap().TRIGGER_RIGHT.update(
|
||||
(event.getAxisValue( MotionEvent.AXIS_RTRIGGER) > 0.5)
|
||||
|| (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)
|
||||
|| (mModifierSwappedAxis && event.getAxisValue(MotionEvent.AXIS_RZ) > 0.5) );
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyGUISizeChange(int newSize){
|
||||
//Change the pointer size to match UI
|
||||
int size = (int) ((22 * newSize) / scaleFactor);
|
||||
pointerView.post(() -> pointerView.setLayoutParams(new FrameLayout.LayoutParams(size, size)));
|
||||
int size = (int) ((22 * newSize) / mScaleFactor);
|
||||
mPointerImageView.post(() -> mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if a gamepad supports analog triggers
|
||||
* @param inputDevice The input device with all the MotionRange
|
||||
* @return Whether the gamepad supports analog triggers
|
||||
*/
|
||||
private boolean supportAnalogTriggers(InputDevice inputDevice){
|
||||
for(InputDevice.MotionRange motionRange : inputDevice.getMotionRanges()){
|
||||
int axis = motionRange.getAxis();
|
||||
|
||||
if( axis == MotionEvent.AXIS_BRAKE || axis == MotionEvent.AXIS_GAS ||
|
||||
axis == MotionEvent.AXIS_LTRIGGER || axis == MotionEvent.AXIS_RTRIGGER ||
|
||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_Z) ||
|
||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_RZ)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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){
|
||||
sendButton(event.getKeyCode(), event.getAction());
|
||||
}
|
||||
@@ -403,7 +228,7 @@ public class Gamepad {
|
||||
|
||||
|
||||
default:
|
||||
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isDown);
|
||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isDown);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -418,11 +243,11 @@ public class Gamepad {
|
||||
if(isDown) CallbackBridge.sendScroll(0, 1);
|
||||
break;
|
||||
|
||||
case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT:
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
|
||||
case LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT:
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
|
||||
break;
|
||||
case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT:
|
||||
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
|
||||
case LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT:
|
||||
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
|
||||
break;
|
||||
|
||||
|
||||
@@ -443,4 +268,180 @@ public class Gamepad {
|
||||
return ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
|
||||
|| GamepadDpad.isDpadEvent(event) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the new mouse position, computing the delta
|
||||
* @param frameTimeNanos The time to render the frame, used to compute mouse delta
|
||||
*/
|
||||
private void tick(long frameTimeNanos){
|
||||
//update mouse position
|
||||
if(mLastHorizontalValue != 0 || mLastVerticalValue != 0){
|
||||
GamepadJoystick currentJoystick = mLastGrabbingState ? mLeftJoystick : mRightJoystick;
|
||||
|
||||
double acceleration = (mMouseMagnitude - currentJoystick.getDeadzone()) / (1 - currentJoystick.getDeadzone());
|
||||
acceleration = Math.pow(acceleration, MOUSE_MAX_ACCELERATION);
|
||||
if(acceleration > 1) acceleration = 1;
|
||||
|
||||
// Compute delta since last tick time
|
||||
float deltaX = (float) (Math.cos(mMouseAngle) * acceleration * mMouseSensitivity);
|
||||
float deltaY = (float) (Math.sin(mMouseAngle) * acceleration * mMouseSensitivity);
|
||||
float deltaTimeScale = ((frameTimeNanos - mLastFrameTime) / 16666666f); // Scale of 1 = 60Hz
|
||||
deltaX *= deltaTimeScale;
|
||||
deltaY *= deltaTimeScale;
|
||||
|
||||
CallbackBridge.mouseX += deltaX;
|
||||
CallbackBridge.mouseY -= deltaY;
|
||||
|
||||
if(!mLastGrabbingState){
|
||||
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
|
||||
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
|
||||
placePointerView((int) (CallbackBridge.mouseX / mScaleFactor), (int) (CallbackBridge.mouseY/ mScaleFactor));
|
||||
}
|
||||
|
||||
mMouse_x = CallbackBridge.mouseX;
|
||||
mMouse_y = CallbackBridge.mouseY;
|
||||
|
||||
//Send the mouse to the game
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
}
|
||||
|
||||
// Update last nano time
|
||||
mLastFrameTime = frameTimeNanos;
|
||||
}
|
||||
|
||||
/** Update the grabbing state, and change the currentMap, mouse position and sensibility */
|
||||
private void updateGrabbingState() {
|
||||
boolean lastGrabbingValue = mLastGrabbingState;
|
||||
mLastGrabbingState = CallbackBridge.isGrabbing();
|
||||
if(lastGrabbingValue == mLastGrabbingState) return;
|
||||
|
||||
// Switch grabbing state then
|
||||
mCurrentMap.resetPressedState();
|
||||
if(mLastGrabbingState){
|
||||
mCurrentMap = mGameMap;
|
||||
mPointerImageView.setVisibility(View.INVISIBLE);
|
||||
mMouseSensitivity = 18;
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentMap = mMenuMap;
|
||||
sendDirectionalKeycode(mCurrentJoystickDirection, false, mGameMap); // removing what we were doing
|
||||
|
||||
mMouse_x = CallbackBridge.windowWidth/2;
|
||||
mMouse_y = CallbackBridge.windowHeight/2;
|
||||
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
|
||||
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
||||
mPointerImageView.setVisibility(View.VISIBLE);
|
||||
// Sensitivity in menu is MC and HARDWARE resolution dependent
|
||||
mMouseSensitivity = 19 * mScaleFactor / mSensitivityFactor;
|
||||
|
||||
}
|
||||
|
||||
private void updateMouseJoystick(MotionEvent event){
|
||||
GamepadJoystick currentJoystick = mLastGrabbingState ? mRightJoystick : mLeftJoystick;
|
||||
float horizontalValue = currentJoystick.getHorizontalAxis(event);
|
||||
float verticalValue = currentJoystick.getVerticalAxis(event);
|
||||
if(horizontalValue != mLastHorizontalValue || verticalValue != mLastVerticalValue){
|
||||
mLastHorizontalValue = horizontalValue;
|
||||
mLastVerticalValue = verticalValue;
|
||||
|
||||
mMouseMagnitude = currentJoystick.getMagnitude(event);
|
||||
mMouseAngle = currentJoystick.getAngleRadian(event);
|
||||
|
||||
tick(System.nanoTime());
|
||||
return;
|
||||
}
|
||||
mLastHorizontalValue = horizontalValue;
|
||||
mLastVerticalValue = verticalValue;
|
||||
|
||||
mMouseMagnitude = currentJoystick.getMagnitude(event);
|
||||
mMouseAngle = currentJoystick.getAngleRadian(event);
|
||||
|
||||
}
|
||||
|
||||
private void updateDirectionalJoystick(MotionEvent event){
|
||||
GamepadJoystick currentJoystick = mLastGrabbingState ? mLeftJoystick : mRightJoystick;
|
||||
|
||||
int lastJoystickDirection = mCurrentJoystickDirection;
|
||||
mCurrentJoystickDirection = currentJoystick.getHeightDirection(event);
|
||||
|
||||
if(mCurrentJoystickDirection == lastJoystickDirection) return;
|
||||
|
||||
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
|
||||
sendDirectionalKeycode(mCurrentJoystickDirection, true, getCurrentMap());
|
||||
}
|
||||
|
||||
private void updateAnalogTriggers(MotionEvent event){
|
||||
if(mModifierAnalogTriggers){
|
||||
getCurrentMap().TRIGGER_LEFT.update(
|
||||
(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5)
|
||||
|| (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)
|
||||
|| (mModifierSwappedAxis &&(event.getAxisValue(MotionEvent.AXIS_Z) > 0.5)) );
|
||||
getCurrentMap().TRIGGER_RIGHT.update(
|
||||
(event.getAxisValue( MotionEvent.AXIS_RTRIGGER) > 0.5)
|
||||
|| (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)
|
||||
|| (mModifierSwappedAxis && event.getAxisValue(MotionEvent.AXIS_RZ) > 0.5) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if a gamepad supports analog triggers
|
||||
* @param inputDevice The input device with all the MotionRange
|
||||
* @return Whether the gamepad supports analog triggers
|
||||
*/
|
||||
private boolean supportAnalogTriggers(InputDevice inputDevice){
|
||||
for(InputDevice.MotionRange motionRange : inputDevice.getMotionRanges()){
|
||||
int axis = motionRange.getAxis();
|
||||
|
||||
if( axis == MotionEvent.AXIS_BRAKE || axis == MotionEvent.AXIS_GAS ||
|
||||
axis == MotionEvent.AXIS_LTRIGGER || axis == MotionEvent.AXIS_RTRIGGER ||
|
||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_Z) ||
|
||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_RZ)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private GamepadMap getCurrentMap(){
|
||||
return mCurrentMap;
|
||||
}
|
||||
|
||||
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){
|
||||
mPointerImageView.setX(x - mPointerImageView.getWidth()/2);
|
||||
mPointerImageView.setY(y - mPointerImageView.getHeight()/2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* Simple button able to store its state and some properties
|
||||
*/
|
||||
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;
|
||||
private boolean mIsDown = false;
|
||||
private boolean mIsToggled = false;
|
||||
|
||||
public void update(KeyEvent event){
|
||||
boolean isKeyDown = (event.getAction() == KeyEvent.ACTION_DOWN);
|
||||
@@ -18,29 +18,29 @@ public class GamepadButton {
|
||||
}
|
||||
|
||||
public void update(boolean isKeyDown){
|
||||
if(isKeyDown != isDown){
|
||||
isDown = isKeyDown;
|
||||
if(isKeyDown != mIsDown){
|
||||
mIsDown = isKeyDown;
|
||||
if(isToggleable){
|
||||
if(isKeyDown){
|
||||
isToggled = !isToggled;
|
||||
Gamepad.sendInput(keycodes, isToggled);
|
||||
mIsToggled = !mIsToggled;
|
||||
Gamepad.sendInput(keycodes, mIsToggled);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Gamepad.sendInput(keycodes, isDown);
|
||||
Gamepad.sendInput(keycodes, mIsDown);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetButtonState(){
|
||||
if(isDown || isToggled){
|
||||
if(mIsDown || mIsToggled){
|
||||
Gamepad.sendInput(keycodes, false);
|
||||
}
|
||||
isDown = false;
|
||||
isToggled = false;
|
||||
mIsDown = false;
|
||||
mIsToggled = false;
|
||||
}
|
||||
|
||||
public boolean isDown(){
|
||||
return isToggleable ? isToggled : isDown;
|
||||
return isToggleable ? mIsToggled : mIsDown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
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;
|
||||
@@ -14,7 +13,7 @@ import static android.view.KeyEvent.KEYCODE_DPAD_UP;
|
||||
|
||||
|
||||
public class GamepadDpad {
|
||||
private int lastKeycode = KEYCODE_DPAD_CENTER;
|
||||
private int mLastKeycode = KEYCODE_DPAD_CENTER;
|
||||
|
||||
/**
|
||||
* Convert the event to a 2 int array: keycode and keyAction, similar to a keyEvent
|
||||
@@ -30,22 +29,22 @@ public class GamepadDpad {
|
||||
// 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;
|
||||
mLastKeycode = KEYCODE_DPAD_LEFT;
|
||||
} else if (Float.compare(xaxis, 1.0f) == 0) {
|
||||
lastKeycode = KEYCODE_DPAD_RIGHT;
|
||||
mLastKeycode = 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;
|
||||
mLastKeycode = KEYCODE_DPAD_UP;
|
||||
} else if (Float.compare(yaxis, 1.0f) == 0) {
|
||||
lastKeycode = KEYCODE_DPAD_DOWN;
|
||||
mLastKeycode = KEYCODE_DPAD_DOWN;
|
||||
}else {
|
||||
//No keycode change
|
||||
action = KeyEvent.ACTION_UP;
|
||||
}
|
||||
|
||||
return new int[]{lastKeycode, action};
|
||||
return new int[]{mLastKeycode, action};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,14 @@ public class GamepadJoystick {
|
||||
public static final int DIRECTION_SOUTH = 6;
|
||||
public static final int DIRECTION_SOUTH_EAST = 7;
|
||||
|
||||
private final InputDevice device;
|
||||
|
||||
private final int verticalAxis;
|
||||
private final int horizontalAxis;
|
||||
private final InputDevice mInputDevice;
|
||||
private final int mVerticalAxis;
|
||||
private final int mHorizontalAxis;
|
||||
|
||||
public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){
|
||||
this.verticalAxis = verticalAxis;
|
||||
this.horizontalAxis = horizontalAxis;
|
||||
this.device = device;
|
||||
|
||||
|
||||
this.mVerticalAxis = verticalAxis;
|
||||
this.mHorizontalAxis = horizontalAxis;
|
||||
this.mInputDevice = device;
|
||||
}
|
||||
|
||||
public double getAngleRadian(MotionEvent event){
|
||||
@@ -48,29 +45,18 @@ public class GamepadJoystick {
|
||||
}
|
||||
|
||||
public double getMagnitude(MotionEvent event){
|
||||
float x = Math.abs(event.getAxisValue(horizontalAxis));
|
||||
float y = Math.abs(event.getAxisValue(verticalAxis));
|
||||
float x = Math.abs(event.getAxisValue(mHorizontalAxis));
|
||||
float y = Math.abs(event.getAxisValue(mVerticalAxis));
|
||||
|
||||
return MathUtils.dist(0,0, x, y);
|
||||
}
|
||||
|
||||
public float getVerticalAxis(MotionEvent event){
|
||||
return applyDeadzone(event, verticalAxis);
|
||||
return applyDeadzone(event, mVerticalAxis);
|
||||
}
|
||||
|
||||
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);
|
||||
float deadzone = getDeadzone();
|
||||
if (magnitude < deadzone) return 0;
|
||||
|
||||
return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
|
||||
return applyDeadzone(event, mHorizontalAxis);
|
||||
}
|
||||
|
||||
public static boolean isJoystickEvent(MotionEvent event){
|
||||
@@ -91,9 +77,20 @@ public class GamepadJoystick {
|
||||
*/
|
||||
public float getDeadzone() {
|
||||
try{
|
||||
return Math.max(device.getMotionRange(horizontalAxis).getFlat() * 1.9f, 0.2f);
|
||||
return Math.max(mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * 1.9f, 0.2f);
|
||||
}catch (Exception e){
|
||||
return 0.2f;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
float deadzone = getDeadzone();
|
||||
if (magnitude < deadzone) return 0;
|
||||
|
||||
return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||
|
||||
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
|
||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||
|
||||
public class GamepadMap {
|
||||
|
||||
@@ -76,33 +76,33 @@ public class GamepadMap {
|
||||
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.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.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.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.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_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};
|
||||
gameMap.BUTTON_START.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_ESCAPE};
|
||||
gameMap.BUTTON_SELECT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_TAB};
|
||||
|
||||
return gameMap;
|
||||
}
|
||||
@@ -113,10 +113,10 @@ public class GamepadMap {
|
||||
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.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};
|
||||
@@ -124,9 +124,9 @@ public class GamepadMap {
|
||||
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.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};
|
||||
@@ -137,7 +137,7 @@ public class GamepadMap {
|
||||
menuMap.THUMBSTICK_LEFT.keycodes = new int[]{};
|
||||
menuMap.THUMBSTICK_RIGHT.keycodes = new int[]{};
|
||||
|
||||
menuMap.BUTTON_START.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE};
|
||||
menuMap.BUTTON_START.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_ESCAPE};
|
||||
menuMap.BUTTON_SELECT.keycodes = new int[]{};
|
||||
|
||||
return menuMap;
|
||||
|
||||
@@ -43,11 +43,11 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
|
||||
private TextView mDeleteTextView;
|
||||
private TextView mCloneTextView;
|
||||
|
||||
private final ControlButton editedButton;
|
||||
private final ControlButton mEditedButton;
|
||||
|
||||
public ActionPopupWindow(HandleView handleView, ControlButton button){
|
||||
super(handleView);
|
||||
this.editedButton = button;
|
||||
this.mEditedButton = button;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,18 +97,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
|
||||
public void onClick(final View view) {
|
||||
if (view == mEditTextView) {
|
||||
|
||||
if(editedButton instanceof ControlSubButton){
|
||||
new EditControlSubButtonPopup((ControlSubButton) editedButton);
|
||||
if(mEditedButton instanceof ControlSubButton){
|
||||
new EditControlSubButtonPopup((ControlSubButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(editedButton instanceof ControlDrawer){
|
||||
new EditControlDrawerPopup((ControlDrawer) editedButton);
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
new EditControlDrawerPopup((ControlDrawer) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(editedButton instanceof ControlButton){
|
||||
new EditControlButtonPopup((ControlButton) editedButton);
|
||||
if(mEditedButton instanceof ControlButton){
|
||||
new EditControlButtonPopup((ControlButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,18 +121,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
|
||||
alertBuilder.setPositiveButton(R.string.global_remove, (p1, p2) -> {
|
||||
ControlLayout layout = ((ControlLayout) mHandleView.mView.getParent());
|
||||
|
||||
if(editedButton instanceof ControlSubButton){
|
||||
layout.removeControlSubButton((ControlSubButton) editedButton);
|
||||
if(mEditedButton instanceof ControlSubButton){
|
||||
layout.removeControlSubButton((ControlSubButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(editedButton instanceof ControlDrawer){
|
||||
layout.removeControlDrawer((ControlDrawer) editedButton);
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
layout.removeControlDrawer((ControlDrawer) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(editedButton instanceof ControlButton){
|
||||
layout.removeControlButton((ControlButton) editedButton);
|
||||
if(mEditedButton instanceof ControlButton){
|
||||
layout.removeControlButton((ControlButton) mEditedButton);
|
||||
}
|
||||
|
||||
layout.removeControlButton(mHandleView.mView);
|
||||
@@ -140,18 +140,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
|
||||
alertBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
alertBuilder.show();
|
||||
}else if(view == mCloneTextView) {
|
||||
if(editedButton instanceof ControlDrawer){
|
||||
ControlDrawerData cloneData = new ControlDrawerData(((ControlDrawer)editedButton).getDrawerData());
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
ControlDrawerData cloneData = new ControlDrawerData(((ControlDrawer) mEditedButton).getDrawerData());
|
||||
cloneData.properties.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.properties.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addDrawer(cloneData);
|
||||
}else if(editedButton instanceof ControlSubButton){
|
||||
ControlData cloneData = new ControlData(editedButton.getProperties());
|
||||
}else if(mEditedButton instanceof ControlSubButton){
|
||||
ControlData cloneData = new ControlData(mEditedButton.getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addSubButton(((ControlSubButton) editedButton).parentDrawer, cloneData);
|
||||
((ControlLayout) mHandleView.mView.getParent()).addSubButton(((ControlSubButton) mEditedButton).parentDrawer, cloneData);
|
||||
}else{
|
||||
ControlData cloneData = new ControlData(editedButton.getProperties());
|
||||
ControlData cloneData = new ControlData(mEditedButton.getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addControlButton(cloneData);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
@@ -8,7 +7,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.SeekBar;
|
||||
@@ -29,103 +27,103 @@ import static net.kdt.pojavlaunch.customcontrols.handleview.ActionPopupWindow.se
|
||||
|
||||
public class EditControlButtonPopup {
|
||||
|
||||
protected AlertDialog dialog;
|
||||
protected View v;
|
||||
protected AlertDialog.Builder builder;
|
||||
protected AlertDialog mDialog;
|
||||
protected View mRootView;
|
||||
protected AlertDialog.Builder mBuilder;
|
||||
|
||||
protected EditText editName;
|
||||
protected Spinner[] spinnersKeycode;
|
||||
protected EditText mNameEditText;
|
||||
protected Spinner[] mKeycodeSpinners;
|
||||
|
||||
protected CheckBox checkToggle;
|
||||
protected CheckBox checkPassThrough;
|
||||
protected CheckBox checkBoxSwipeable;
|
||||
protected CheckBox checkDynamicPosition;
|
||||
protected CheckBox mToggleCheckbox;
|
||||
protected CheckBox mPassthroughCheckbox;
|
||||
protected CheckBox mSwipeableCheckbox;
|
||||
protected CheckBox mDynamicPositionCheckbox;
|
||||
|
||||
protected EditText editWidth;
|
||||
protected EditText editHeight;
|
||||
protected EditText editDynamicX;
|
||||
protected EditText editDynamicY;
|
||||
protected EditText mWidthEditText;
|
||||
protected EditText mHeightEditText;
|
||||
protected EditText mDynamicXEditText;
|
||||
protected EditText mDynamicYEditText;
|
||||
|
||||
protected SeekBar seekBarOpacity;
|
||||
protected SeekBar seekBarCornerRadius;
|
||||
protected SeekBar seekBarStrokeWidth;
|
||||
protected SeekBar mOpacitySeekbar;
|
||||
protected SeekBar mCornerRadiusSeekbar;
|
||||
protected SeekBar mStrokeWidthSeekbar;
|
||||
|
||||
protected ImageButton buttonBackgroundColor;
|
||||
protected ImageButton buttonStrokeColor;
|
||||
protected ImageButton mBackgroundColorButton;
|
||||
protected ImageButton mStrokeColorButton;
|
||||
|
||||
protected TextView textOpacity;
|
||||
protected TextView textCornerRadius;
|
||||
protected TextView textStrokeWidth;
|
||||
protected TextView textStrokeColor;
|
||||
protected TextView mOpacityTextView;
|
||||
protected TextView mCornerRadiusTextView;
|
||||
protected TextView mStrokeWidthTextView;
|
||||
protected TextView mStrokeColorTextView;
|
||||
|
||||
protected final ControlButton button;
|
||||
protected final ControlData properties;
|
||||
protected final ControlButton mControlButton;
|
||||
protected final ControlData mProperties;
|
||||
|
||||
protected ArrayAdapter<String> adapter;
|
||||
protected String[] specialArr;
|
||||
protected ArrayAdapter<String> mAdapter;
|
||||
protected String[] mSpecialArray;
|
||||
|
||||
|
||||
public EditControlButtonPopup(ControlButton button){
|
||||
this.button = button;
|
||||
this.properties = button.getProperties();
|
||||
this.mControlButton = button;
|
||||
this.mProperties = button.getProperties();
|
||||
|
||||
initializeEditDialog(button.getContext());
|
||||
|
||||
//Create the finalized dialog
|
||||
dialog = builder.create();
|
||||
dialog.setOnShowListener(dialogInterface -> setEditDialogValues());
|
||||
mDialog = mBuilder.create();
|
||||
mDialog.setOnShowListener(dialogInterface -> setEditDialogValues());
|
||||
|
||||
dialog.show();
|
||||
mDialog.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);
|
||||
mRootView = layoutInflater.inflate(R.layout.dialog_control_button_setting,null);
|
||||
|
||||
builder = new AlertDialog.Builder(ctx);
|
||||
builder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, properties.name));
|
||||
builder.setView(v);
|
||||
mBuilder = new AlertDialog.Builder(ctx);
|
||||
mBuilder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, mProperties.name));
|
||||
mBuilder.setView(mRootView);
|
||||
|
||||
//Linking a lot of stuff
|
||||
editName = v.findViewById(R.id.editName_editText);
|
||||
mNameEditText = mRootView.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)
|
||||
mKeycodeSpinners = new Spinner[]{
|
||||
mRootView.findViewById(R.id.editMapping_spinner_1),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_2),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_3),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_4)
|
||||
};
|
||||
|
||||
checkToggle = v.findViewById(R.id.checkboxToggle);
|
||||
checkPassThrough = v.findViewById(R.id.checkboxPassThrough);
|
||||
checkBoxSwipeable = v.findViewById(R.id.checkboxSwipeable);
|
||||
mToggleCheckbox = mRootView.findViewById(R.id.checkboxToggle);
|
||||
mPassthroughCheckbox = mRootView.findViewById(R.id.checkboxPassThrough);
|
||||
mSwipeableCheckbox = mRootView.findViewById(R.id.checkboxSwipeable);
|
||||
|
||||
editWidth = v.findViewById(R.id.editSize_editTextX);
|
||||
editHeight = v.findViewById(R.id.editSize_editTextY);
|
||||
mWidthEditText = mRootView.findViewById(R.id.editSize_editTextX);
|
||||
mHeightEditText = mRootView.findViewById(R.id.editSize_editTextY);
|
||||
|
||||
editDynamicX = v.findViewById(R.id.editDynamicPositionX_editText);
|
||||
editDynamicY = v.findViewById(R.id.editDynamicPositionY_editText);
|
||||
mDynamicXEditText = mRootView.findViewById(R.id.editDynamicPositionX_editText);
|
||||
mDynamicYEditText = mRootView.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);
|
||||
mOpacitySeekbar = mRootView.findViewById(R.id.editButtonOpacity_seekbar);
|
||||
mCornerRadiusSeekbar = mRootView.findViewById(R.id.editCornerRadius_seekbar);
|
||||
mStrokeWidthSeekbar = mRootView.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);
|
||||
if(seekBar.equals(mCornerRadiusSeekbar)) {
|
||||
setPercentageText(mCornerRadiusTextView, i);
|
||||
return;
|
||||
}
|
||||
if(seekBar.equals(seekBarOpacity)) {
|
||||
setPercentageText(textOpacity, i);
|
||||
if(seekBar.equals(mOpacitySeekbar)) {
|
||||
setPercentageText(mOpacityTextView, i);
|
||||
return;
|
||||
}
|
||||
if(seekBar.equals(seekBarStrokeWidth)) {
|
||||
setPercentageText(textStrokeWidth, i);
|
||||
textStrokeColor.setVisibility(i == 0 ? View.GONE : View.VISIBLE);
|
||||
if(seekBar.equals(mStrokeWidthSeekbar)) {
|
||||
setPercentageText(mStrokeWidthTextView, i);
|
||||
mStrokeColorTextView.setVisibility(i == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,43 +134,43 @@ public class EditControlButtonPopup {
|
||||
};
|
||||
|
||||
//Add listeners, too bad I don't need all the methods
|
||||
seekBarOpacity.setOnSeekBarChangeListener(changeListener);
|
||||
seekBarCornerRadius.setOnSeekBarChangeListener(changeListener);
|
||||
seekBarStrokeWidth.setOnSeekBarChangeListener(changeListener);
|
||||
mOpacitySeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
mCornerRadiusSeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
mStrokeWidthSeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
|
||||
buttonBackgroundColor = v.findViewById(R.id.editBackgroundColor_imageButton);
|
||||
buttonStrokeColor = v.findViewById(R.id.editStrokeColor_imageButton);
|
||||
mBackgroundColorButton = mRootView.findViewById(R.id.editBackgroundColor_imageButton);
|
||||
mStrokeColorButton = mRootView.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);
|
||||
textStrokeColor = v.findViewById(R.id.editStrokeColor_textView);
|
||||
mOpacityTextView = mRootView.findViewById(R.id.editButtonOpacity_textView_percent);
|
||||
mCornerRadiusTextView = mRootView.findViewById(R.id.editCornerRadius_textView_percent);
|
||||
mStrokeWidthTextView = mRootView.findViewById(R.id.editStrokeWidth_textView_percent);
|
||||
mStrokeColorTextView = mRootView.findViewById(R.id.editStrokeColor_textView);
|
||||
|
||||
checkDynamicPosition = v.findViewById(R.id.checkboxDynamicPosition);
|
||||
checkDynamicPosition.setOnCheckedChangeListener((btn, checked) -> {
|
||||
editDynamicX.setEnabled(checked);
|
||||
editDynamicY.setEnabled(checked);
|
||||
mDynamicPositionCheckbox = mRootView.findViewById(R.id.checkboxDynamicPosition);
|
||||
mDynamicPositionCheckbox.setOnCheckedChangeListener((btn, checked) -> {
|
||||
mDynamicXEditText.setEnabled(checked);
|
||||
mDynamicYEditText.setEnabled(checked);
|
||||
});
|
||||
|
||||
|
||||
//Initialize adapter for keycodes
|
||||
adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
|
||||
mAdapter = 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];
|
||||
mSpecialArray = new String[oldSpecialArr.length];
|
||||
for (int i = 0; i < mSpecialArray.length; i++) {
|
||||
mSpecialArray[i] = "SPECIAL_" + oldSpecialArr[mSpecialArray.length - i - 1];
|
||||
}
|
||||
adapter.addAll(specialArr);
|
||||
adapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
mAdapter.addAll(mSpecialArray);
|
||||
mAdapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
|
||||
mAdapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
|
||||
for (Spinner spinner : spinnersKeycode) {
|
||||
spinner.setAdapter(adapter);
|
||||
for (Spinner spinner : mKeycodeSpinners) {
|
||||
spinner.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
//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));
|
||||
mBackgroundColorButton.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit background color", true, mBackgroundColorButton));
|
||||
mStrokeColorButton.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit stroke color", false, mStrokeColorButton));
|
||||
|
||||
|
||||
//Set dialog buttons behavior
|
||||
@@ -187,34 +185,34 @@ public class EditControlButtonPopup {
|
||||
|
||||
protected void setupDialogButtons(){
|
||||
//Set dialog buttons behavior
|
||||
builder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> {
|
||||
if(!hasPropertiesErrors(dialog.getContext())){
|
||||
mBuilder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> {
|
||||
if(!hasPropertiesErrors(mDialog.getContext())){
|
||||
saveProperties();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
mBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
}
|
||||
|
||||
protected void hideUselessViews(){
|
||||
(v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
|
||||
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
editDynamicX.setVisibility(View.GONE);
|
||||
editDynamicY.setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
|
||||
//Hide the color choice if the width is 0.
|
||||
textStrokeColor.setVisibility(properties.strokeWidth == 0 ? View.GONE : View.VISIBLE);
|
||||
mStrokeColorTextView.setVisibility(mProperties.strokeWidth == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
protected void defineDynamicCheckChange(){
|
||||
checkDynamicPosition.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||
mDynamicPositionCheckbox.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||
int visibility = b ? View.VISIBLE : View.GONE;
|
||||
|
||||
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(visibility);
|
||||
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(visibility);
|
||||
editDynamicX.setVisibility(visibility);
|
||||
editDynamicY.setVisibility(visibility);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(visibility);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(visibility);
|
||||
mDynamicXEditText.setVisibility(visibility);
|
||||
mDynamicYEditText.setVisibility(visibility);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -226,65 +224,65 @@ public class EditControlButtonPopup {
|
||||
.size((int) Tools.dpToPx(20))
|
||||
.build();
|
||||
|
||||
buttonBackgroundColor.setBackground(drawable);
|
||||
buttonStrokeColor.setBackground(drawable);
|
||||
mBackgroundColorButton.setBackground(drawable);
|
||||
mStrokeColorButton.setBackground(drawable);
|
||||
}
|
||||
|
||||
protected void setEditDialogValues(){
|
||||
|
||||
editName.setText(properties.name);
|
||||
mNameEditText.setText(mProperties.name);
|
||||
|
||||
checkToggle.setChecked(properties.isToggle);
|
||||
checkPassThrough.setChecked(properties.passThruEnabled);
|
||||
checkBoxSwipeable.setChecked(properties.isSwipeable);
|
||||
mToggleCheckbox.setChecked(mProperties.isToggle);
|
||||
mPassthroughCheckbox.setChecked(mProperties.passThruEnabled);
|
||||
mSwipeableCheckbox.setChecked(mProperties.isSwipeable);
|
||||
|
||||
editWidth.setText(Float.toString(properties.getWidth()));
|
||||
editHeight.setText(Float.toString(properties.getHeight()));
|
||||
mWidthEditText.setText(Float.toString(mProperties.getWidth()));
|
||||
mHeightEditText.setText(Float.toString(mProperties.getHeight()));
|
||||
|
||||
editDynamicX.setEnabled(properties.isDynamicBtn);
|
||||
editDynamicY.setEnabled(properties.isDynamicBtn);
|
||||
editDynamicX.setText(properties.dynamicX);
|
||||
mDynamicXEditText.setEnabled(mProperties.isDynamicBtn);
|
||||
mDynamicYEditText.setEnabled(mProperties.isDynamicBtn);
|
||||
mDynamicXEditText.setText(mProperties.dynamicX);
|
||||
|
||||
editDynamicY.setText(properties.dynamicY);
|
||||
mDynamicYEditText.setText(mProperties.dynamicY);
|
||||
|
||||
seekBarOpacity.setProgress((int) (properties.opacity*100));
|
||||
seekBarStrokeWidth.setProgress(properties.strokeWidth);
|
||||
seekBarCornerRadius.setProgress((int)properties.cornerRadius);
|
||||
mOpacitySeekbar.setProgress((int) (mProperties.opacity*100));
|
||||
mStrokeWidthSeekbar.setProgress(mProperties.strokeWidth);
|
||||
mCornerRadiusSeekbar.setProgress((int) mProperties.cornerRadius);
|
||||
|
||||
buttonBackgroundColor.setImageDrawable(new ColorDrawable(properties.bgColor));
|
||||
buttonStrokeColor.setImageDrawable(new ColorDrawable(properties.strokeColor));
|
||||
mBackgroundColorButton.setImageDrawable(new ColorDrawable(mProperties.bgColor));
|
||||
mStrokeColorButton.setImageDrawable(new ColorDrawable(mProperties.strokeColor));
|
||||
|
||||
setPercentageText(textCornerRadius,seekBarCornerRadius.getProgress());
|
||||
setPercentageText(textOpacity,seekBarOpacity.getProgress());
|
||||
setPercentageText(textStrokeWidth,seekBarStrokeWidth.getProgress());
|
||||
setPercentageText(mCornerRadiusTextView, mCornerRadiusSeekbar.getProgress());
|
||||
setPercentageText(mOpacityTextView, mOpacitySeekbar.getProgress());
|
||||
setPercentageText(mStrokeWidthTextView, mStrokeWidthSeekbar.getProgress());
|
||||
|
||||
checkDynamicPosition.setChecked(properties.isDynamicBtn);
|
||||
mDynamicPositionCheckbox.setChecked(mProperties.isDynamicBtn);
|
||||
|
||||
for(int i=0; i< properties.keycodes.length; i++){
|
||||
if (properties.keycodes[i] < 0) {
|
||||
spinnersKeycode[i].setSelection(properties.keycodes[i] + specialArr.length);
|
||||
for(int i = 0; i< mProperties.keycodes.length; i++){
|
||||
if (mProperties.keycodes[i] < 0) {
|
||||
mKeycodeSpinners[i].setSelection(mProperties.keycodes[i] + mSpecialArray.length);
|
||||
} else {
|
||||
spinnersKeycode[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(properties.keycodes[i]) + specialArr.length);
|
||||
mKeycodeSpinners[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(mProperties.keycodes[i]) + mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean hasPropertiesErrors(Context ctx){
|
||||
if (editName.getText().toString().isEmpty()) {
|
||||
editName.setError(ctx.getResources().getString(R.string.global_error_field_empty));
|
||||
if (mNameEditText.getText().toString().isEmpty()) {
|
||||
mNameEditText.setError(ctx.getResources().getString(R.string.global_error_field_empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (properties.isDynamicBtn) {
|
||||
if (mProperties.isDynamicBtn) {
|
||||
|
||||
int errorAt = 0;
|
||||
try {
|
||||
properties.insertDynamicPos(editDynamicX.getText().toString());
|
||||
mProperties.insertDynamicPos(mDynamicXEditText.getText().toString());
|
||||
errorAt = 1;
|
||||
properties.insertDynamicPos(editDynamicY.getText().toString());
|
||||
mProperties.insertDynamicPos(mDynamicYEditText.getText().toString());
|
||||
} catch (Throwable th) {
|
||||
(errorAt == 0 ? editDynamicX : editDynamicY).setError(th.getMessage());
|
||||
(errorAt == 0 ? mDynamicXEditText : mDynamicYEditText).setError(th.getMessage());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -295,36 +293,36 @@ public class EditControlButtonPopup {
|
||||
|
||||
protected void saveProperties(){
|
||||
//This method assumes there are no error.
|
||||
properties.name = editName.getText().toString();
|
||||
mProperties.name = mNameEditText.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;
|
||||
for(int i = 0; i< mKeycodeSpinners.length; ++i){
|
||||
if (mKeycodeSpinners[i].getSelectedItemPosition() < mSpecialArray.length) {
|
||||
mProperties.keycodes[i] = mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length;
|
||||
} else {
|
||||
properties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(spinnersKeycode[i].getSelectedItemPosition() - specialArr.length);
|
||||
mProperties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
|
||||
properties.opacity = seekBarOpacity.getProgress()/100f;
|
||||
properties.strokeWidth = seekBarStrokeWidth.getProgress();
|
||||
properties.cornerRadius = seekBarCornerRadius.getProgress();
|
||||
mProperties.opacity = mOpacitySeekbar.getProgress()/100f;
|
||||
mProperties.strokeWidth = mStrokeWidthSeekbar.getProgress();
|
||||
mProperties.cornerRadius = mCornerRadiusSeekbar.getProgress();
|
||||
|
||||
properties.bgColor = ((ColorDrawable)buttonBackgroundColor.getDrawable()).getColor();
|
||||
properties.strokeColor = ((ColorDrawable) buttonStrokeColor.getDrawable()).getColor();
|
||||
mProperties.bgColor = ((ColorDrawable) mBackgroundColorButton.getDrawable()).getColor();
|
||||
mProperties.strokeColor = ((ColorDrawable) mStrokeColorButton.getDrawable()).getColor();
|
||||
|
||||
properties.isToggle = checkToggle.isChecked();
|
||||
properties.passThruEnabled = checkPassThrough.isChecked();
|
||||
properties.isSwipeable = checkBoxSwipeable.isChecked();
|
||||
mProperties.isToggle = mToggleCheckbox.isChecked();
|
||||
mProperties.passThruEnabled = mPassthroughCheckbox.isChecked();
|
||||
mProperties.isSwipeable = mSwipeableCheckbox.isChecked();
|
||||
|
||||
properties.setWidth(Float.parseFloat(editWidth.getText().toString()));
|
||||
properties.setHeight(Float.parseFloat(editHeight.getText().toString()));
|
||||
mProperties.setWidth(Float.parseFloat(mWidthEditText.getText().toString()));
|
||||
mProperties.setHeight(Float.parseFloat(mHeightEditText.getText().toString()));
|
||||
|
||||
properties.isDynamicBtn = checkDynamicPosition.isChecked();
|
||||
if(!editDynamicX.getText().toString().isEmpty()) properties.dynamicX = editDynamicX.getText().toString();
|
||||
if(!editDynamicY.getText().toString().isEmpty()) properties.dynamicY = editDynamicY.getText().toString();
|
||||
mProperties.isDynamicBtn = mDynamicPositionCheckbox.isChecked();
|
||||
if(!mDynamicXEditText.getText().toString().isEmpty()) mProperties.dynamicX = mDynamicXEditText.getText().toString();
|
||||
if(!mDynamicYEditText.getText().toString().isEmpty()) mProperties.dynamicY = mDynamicYEditText.getText().toString();
|
||||
|
||||
button.updateProperties();
|
||||
mControlButton.updateProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,62 +14,62 @@ import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
|
||||
public class EditControlDrawerPopup extends EditControlButtonPopup{
|
||||
private Spinner spinnerOrientation;
|
||||
private Spinner mOrientationSpinner;
|
||||
|
||||
|
||||
private ControlDrawer drawer;
|
||||
private ControlDrawerData drawerData;
|
||||
private final ControlDrawer mDrawer;
|
||||
private final ControlDrawerData mDrawerData;
|
||||
|
||||
public EditControlDrawerPopup(ControlDrawer editedButton) {
|
||||
super(editedButton);
|
||||
drawer = editedButton;
|
||||
drawerData = editedButton.getDrawerData();
|
||||
mDrawer = editedButton;
|
||||
mDrawerData = 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);
|
||||
(mRootView.findViewById(R.id.editMapping_textView)).setVisibility(View.GONE);
|
||||
mPassthroughCheckbox.setVisibility(View.GONE);
|
||||
mToggleCheckbox.setVisibility(View.GONE);
|
||||
mSwipeableCheckbox.setVisibility(View.GONE);
|
||||
|
||||
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
editDynamicX.setVisibility(View.GONE);
|
||||
editDynamicY.setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeEditDialog(Context ctx) {
|
||||
super.initializeEditDialog(ctx);
|
||||
|
||||
spinnerOrientation = v.findViewById(R.id.editOrientation_spinner);
|
||||
mOrientationSpinner = mRootView.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);
|
||||
mOrientationSpinner.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEditDialogValues() {
|
||||
super.setEditDialogValues();
|
||||
|
||||
spinnerOrientation.setSelection(ControlDrawerData.orientationToInt(drawerData.orientation));
|
||||
mOrientationSpinner.setSelection(ControlDrawerData.orientationToInt(mDrawerData.orientation));
|
||||
|
||||
|
||||
//Using the dialog to replace the button behavior allows us not to dismiss the window
|
||||
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(v -> {
|
||||
ControlLayout layout = (ControlLayout) drawer.getParent();
|
||||
ControlData controlData = new ControlData(drawerData.properties);
|
||||
mDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(v -> {
|
||||
ControlLayout layout = (ControlLayout) mDrawer.getParent();
|
||||
ControlData controlData = new ControlData(mDrawerData.properties);
|
||||
controlData.name = "new";
|
||||
layout.addSubButton(drawer, controlData);
|
||||
layout.addSubButton(mDrawer, controlData);
|
||||
|
||||
Context ctx = dialog.getContext();
|
||||
Context ctx = mDialog.getContext();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.customctrl_add_subbutton_message,
|
||||
drawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
|
||||
mDrawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
}
|
||||
@@ -78,13 +78,13 @@ public class EditControlDrawerPopup extends EditControlButtonPopup{
|
||||
protected void setupDialogButtons() {
|
||||
super.setupDialogButtons();
|
||||
|
||||
builder.setNeutralButton(v.getResources().getString(R.string.customctrl_addsubbutton), null);
|
||||
mBuilder.setNeutralButton(mRootView.getResources().getString(R.string.customctrl_addsubbutton), null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveProperties() {
|
||||
drawerData.orientation = ControlDrawerData.intToOrientation(spinnerOrientation.getSelectedItemPosition());
|
||||
mDrawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition());
|
||||
super.saveProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,15 @@ public class EditControlSubButtonPopup extends EditControlButtonPopup{
|
||||
|
||||
@Override
|
||||
protected void hideUselessViews() {
|
||||
(v.findViewById(R.id.editSize_textView)).setVisibility(View.GONE);
|
||||
(v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editSize_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
|
||||
checkDynamicPosition.setVisibility(View.GONE);
|
||||
mDynamicPositionCheckbox.setVisibility(View.GONE);
|
||||
|
||||
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
editDynamicX.setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
|
||||
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
editDynamicY.setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,8 @@ import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
|
||||
|
||||
public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener
|
||||
{
|
||||
public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener {
|
||||
protected Drawable mDrawable;
|
||||
protected Drawable mDrawableLtr;
|
||||
protected Drawable mDrawableRtl;
|
||||
private final PopupWindow mContainer;
|
||||
// Position with respect to the parent TextView
|
||||
@@ -65,12 +63,19 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
// int mWindowPosX, mWindowPosY;
|
||||
|
||||
private PositionListener mPositionListener;
|
||||
public PositionListener getPositionListener() {
|
||||
if (mPositionListener == null) {
|
||||
mPositionListener = new PositionListener(mView);
|
||||
}
|
||||
return mPositionListener;
|
||||
}
|
||||
|
||||
// Touch-up filter: number of previous positions remembered
|
||||
private static final int HISTORY_SIZE = 5;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
|
||||
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
|
||||
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
|
||||
private int mPreviousOffsetIndex = 0;
|
||||
private int mNumberPreviousOffsets = 0;
|
||||
|
||||
// Addition
|
||||
private float mDownX, mDownY;
|
||||
|
||||
|
||||
public HandleView(ControlButton view) {
|
||||
super(view.getContext());
|
||||
@@ -86,8 +91,7 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
|
||||
mContainer.setContentView(this);
|
||||
|
||||
mDrawableLtr = view.getContext().getDrawable(R.drawable.text_select_handle_left_material);
|
||||
mDrawableRtl = view.getContext().getDrawable(R.drawable.text_select_handle_right_material);
|
||||
mDrawableRtl = view.getContext().getDrawable(R.drawable.ic_view_handle);
|
||||
mMinSize = view.getContext().getResources().getDimensionPixelSize(R.dimen.text_handle_min_size);
|
||||
|
||||
setOnLongClickListener(this);
|
||||
@@ -99,11 +103,103 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
mIdealVerticalOffset = 0.7f * handleHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas c) {
|
||||
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||
final int left = getHorizontalOffset();
|
||||
|
||||
mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
|
||||
mDrawable.draw(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
ViewGroup.LayoutParams params = mView.getLayoutParams();
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
startTouchUpFilter(getCurrentCursorOffset());
|
||||
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
|
||||
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
|
||||
|
||||
final PositionListener positionListener = getPositionListener();
|
||||
mLastParentX = positionListener.getPositionX();
|
||||
mLastParentY = positionListener.getPositionY();
|
||||
mIsDragging = true;
|
||||
|
||||
// MOD: Addition
|
||||
mDownX = ev.getRawX();
|
||||
mDownY = ev.getRawY();
|
||||
mDownWidth = params.width;
|
||||
mDownHeight = params.height;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final float rawX = ev.getRawX();
|
||||
final float rawY = ev.getRawY();
|
||||
|
||||
// Vertical hysteresis: vertical down movement tends to snap to ideal offset
|
||||
final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
|
||||
final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
|
||||
float newVerticalOffset;
|
||||
if (previousVerticalOffset < mIdealVerticalOffset) {
|
||||
newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
|
||||
} else {
|
||||
newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
|
||||
}
|
||||
mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
|
||||
|
||||
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
|
||||
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
|
||||
|
||||
int newWidth = (int) (mDownWidth + (rawX - mDownX));
|
||||
int newHeight = (int) (mDownHeight + (rawY - mDownY));
|
||||
|
||||
// mDownX = rawX;
|
||||
// mDownY = rawY;
|
||||
|
||||
params.width = Math.max(50, newWidth);
|
||||
params.height = Math.max(50, newHeight);
|
||||
|
||||
mView.setLayoutParams(params);
|
||||
|
||||
updatePosition(newPosX, newPosY);
|
||||
// break;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
filterOnTouchUp();
|
||||
mIsDragging = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mIsDragging = false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PositionListener getPositionListener() {
|
||||
if (mPositionListener == null) {
|
||||
mPositionListener = new PositionListener(mView);
|
||||
}
|
||||
return mPositionListener;
|
||||
}
|
||||
|
||||
protected void updateDrawable() {
|
||||
// final int offset = getCurrentCursorOffset();
|
||||
final boolean isRtlCharAtOffset = true; // mView.getLayout().isRtlCharAt(offset);
|
||||
mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
|
||||
mDrawable = mDrawableRtl; //isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
|
||||
mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
|
||||
mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
|
||||
}
|
||||
@@ -111,14 +207,7 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
|
||||
protected abstract int getHorizontalGravity(boolean isRtlRun);
|
||||
|
||||
// Touch-up filter: number of previous positions remembered
|
||||
private static final int HISTORY_SIZE = 5;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
|
||||
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
|
||||
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
|
||||
private int mPreviousOffsetIndex = 0;
|
||||
private int mNumberPreviousOffsets = 0;
|
||||
|
||||
|
||||
private void startTouchUpFilter(int offset) {
|
||||
mNumberPreviousOffsets = 0;
|
||||
@@ -152,11 +241,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
return mNumberPreviousOffsets > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
|
||||
}
|
||||
|
||||
private int getPreferredWidth() {
|
||||
return Math.max(mDrawable.getIntrinsicWidth(), mMinSize);
|
||||
}
|
||||
@@ -283,15 +367,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas c) {
|
||||
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||
final int left = getHorizontalOffset();
|
||||
|
||||
mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
|
||||
mDrawable.draw(c);
|
||||
}
|
||||
|
||||
private int getHorizontalOffset() {
|
||||
final int width = getPreferredWidth();
|
||||
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||
@@ -315,81 +390,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Addition
|
||||
private float mDownX, mDownY;
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
ViewGroup.LayoutParams params = mView.getLayoutParams();
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
startTouchUpFilter(getCurrentCursorOffset());
|
||||
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
|
||||
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
|
||||
|
||||
final PositionListener positionListener = getPositionListener();
|
||||
mLastParentX = positionListener.getPositionX();
|
||||
mLastParentY = positionListener.getPositionY();
|
||||
mIsDragging = true;
|
||||
|
||||
// MOD: Addition
|
||||
mDownX = ev.getRawX();
|
||||
mDownY = ev.getRawY();
|
||||
mDownWidth = params.width;
|
||||
mDownHeight = params.height;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final float rawX = ev.getRawX();
|
||||
final float rawY = ev.getRawY();
|
||||
|
||||
// Vertical hysteresis: vertical down movement tends to snap to ideal offset
|
||||
final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
|
||||
final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
|
||||
float newVerticalOffset;
|
||||
if (previousVerticalOffset < mIdealVerticalOffset) {
|
||||
newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
|
||||
} else {
|
||||
newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
|
||||
}
|
||||
mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
|
||||
|
||||
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
|
||||
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
|
||||
|
||||
int newWidth = (int) (mDownWidth + (rawX - mDownX));
|
||||
int newHeight = (int) (mDownHeight + (rawY - mDownY));
|
||||
|
||||
// mDownX = rawX;
|
||||
// mDownY = rawY;
|
||||
|
||||
params.width = Math.max(50, newWidth);
|
||||
params.height = Math.max(50, newHeight);
|
||||
|
||||
mView.setLayoutParams(params);
|
||||
|
||||
updatePosition(newPosX, newPosY);
|
||||
// break;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
filterOnTouchUp();
|
||||
mIsDragging = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mIsDragging = false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDragging() {
|
||||
return mIsDragging;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ import android.view.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
|
||||
|
||||
public class SelectionEndHandleView extends HandleView
|
||||
{
|
||||
public class SelectionEndHandleView extends HandleView {
|
||||
public SelectionEndHandleView(ControlButton view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
public interface ViewPositionListener {
|
||||
public void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled);
|
||||
void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled);
|
||||
}
|
||||
|
||||
@@ -17,24 +17,24 @@ public final class ExtraCore {
|
||||
private ExtraCore(){}
|
||||
|
||||
// Singleton instance
|
||||
private static ExtraCore extraCoreSingleton = null;
|
||||
private static ExtraCore sExtraCoreSingleton = null;
|
||||
|
||||
// Store the key-value pair
|
||||
private final Map<String, Object> valueMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, Object> mValueMap = new ConcurrentHashMap<>();
|
||||
|
||||
// Store what each ExtraListener listen to
|
||||
private final Map<String, ConcurrentLinkedQueue<WeakReference<ExtraListener>>> listenerMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, ConcurrentLinkedQueue<WeakReference<ExtraListener>>> mListenerMap = new ConcurrentHashMap<>();
|
||||
|
||||
// All public methods will pass through this one
|
||||
private static ExtraCore getInstance(){
|
||||
if(extraCoreSingleton == null){
|
||||
if(sExtraCoreSingleton == null){
|
||||
synchronized(ExtraCore.class){
|
||||
if(extraCoreSingleton == null){
|
||||
extraCoreSingleton = new ExtraCore();
|
||||
if(sExtraCoreSingleton == null){
|
||||
sExtraCoreSingleton = new ExtraCore();
|
||||
}
|
||||
}
|
||||
}
|
||||
return extraCoreSingleton;
|
||||
return sExtraCoreSingleton;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,8 +45,8 @@ public final class ExtraCore {
|
||||
public static void setValue(String key, Object value){
|
||||
if(value == null || key == null) return; // null values create an NPE on insertion
|
||||
|
||||
getInstance().valueMap.put(key, value);
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> extraListenerList = getInstance().listenerMap.get(key);
|
||||
getInstance().mValueMap.put(key, value);
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> extraListenerList = getInstance().mListenerMap.get(key);
|
||||
if(extraListenerList == null) return; //No listeners
|
||||
for(WeakReference<ExtraListener> listener : extraListenerList){
|
||||
if(listener.get() == null){
|
||||
@@ -63,17 +63,17 @@ public final class ExtraCore {
|
||||
|
||||
/** @return The value behind the key */
|
||||
public static Object getValue(String key){
|
||||
return getInstance().valueMap.get(key);
|
||||
return getInstance().mValueMap.get(key);
|
||||
}
|
||||
|
||||
/** Remove the key and its value from the valueMap */
|
||||
public static void removeValue(String key){
|
||||
getInstance().valueMap.remove(key);
|
||||
getInstance().mValueMap.remove(key);
|
||||
}
|
||||
|
||||
/** Remove all values */
|
||||
public static void removeAllValues(){
|
||||
getInstance().valueMap.clear();
|
||||
getInstance().mValueMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,11 +82,11 @@ public final class ExtraCore {
|
||||
* @param listener The ExtraListener to link
|
||||
*/
|
||||
public static void addExtraListener(String key, ExtraListener listener){
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
|
||||
// Look for new sets
|
||||
if(listenerList == null){
|
||||
listenerList = new ConcurrentLinkedQueue<>();
|
||||
getInstance().listenerMap.put(key, listenerList);
|
||||
getInstance().mListenerMap.put(key, listenerList);
|
||||
}
|
||||
|
||||
// This is kinda naive, I should look for duplicates
|
||||
@@ -100,11 +100,11 @@ public final class ExtraCore {
|
||||
* @param listener The ExtraListener to unlink
|
||||
*/
|
||||
public static void removeExtraListenerFromValue(String key, ExtraListener listener){
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
|
||||
// Look for new sets
|
||||
if(listenerList == null){
|
||||
listenerList = new ConcurrentLinkedQueue<>();
|
||||
getInstance().listenerMap.put(key, listenerList);
|
||||
getInstance().mListenerMap.put(key, listenerList);
|
||||
}
|
||||
|
||||
// Removes all occurrences of ExtraListener and all null references
|
||||
@@ -122,11 +122,11 @@ public final class ExtraCore {
|
||||
* @param key The key to which ExtraListener are linked
|
||||
*/
|
||||
public static void removeAllExtraListenersFromValue(String key){
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
|
||||
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
|
||||
// Look for new sets
|
||||
if(listenerList == null){
|
||||
listenerList = new ConcurrentLinkedQueue<>();
|
||||
getInstance().listenerMap.put(key, listenerList);
|
||||
getInstance().mListenerMap.put(key, listenerList);
|
||||
}
|
||||
|
||||
listenerList.clear();
|
||||
@@ -136,7 +136,7 @@ public final class ExtraCore {
|
||||
* Remove all ExtraListeners from listening to any value
|
||||
*/
|
||||
public static void removeAllExtraListeners(){
|
||||
getInstance().listenerMap.clear();
|
||||
getInstance().mListenerMap.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.os.*;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
@@ -12,34 +13,33 @@ import android.graphics.*;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class ConsoleFragment extends Fragment
|
||||
{
|
||||
public TextView consoleView;
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.lmaintab_consolelog, container, false);
|
||||
public class ConsoleFragment extends Fragment {
|
||||
public TextView mConsoleView;
|
||||
|
||||
consoleView = (TextView) view.findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
consoleView.setTypeface(Typeface.MONOSPACE);
|
||||
consoleView.setHint(this.getText(R.string.main_nolog));
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.fragment_console_log, container, false);
|
||||
|
||||
mConsoleView = (TextView) view.findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
mConsoleView.setTypeface(Typeface.MONOSPACE);
|
||||
mConsoleView.setHint(this.getText(R.string.main_nolog));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
mConsoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
}
|
||||
|
||||
public void putLog(String str) {
|
||||
if (consoleView == null) {
|
||||
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
if (mConsoleView == null) {
|
||||
mConsoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
}
|
||||
|
||||
consoleView.append(str);
|
||||
mConsoleView.append(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.os.*;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import java.io.*;
|
||||
@@ -11,80 +14,76 @@ import net.kdt.pojavlaunch.*;
|
||||
import android.graphics.*;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class CrashFragment extends Fragment
|
||||
{
|
||||
public static String lastCrashFile = Tools.DIR_DATA + "/lastcrash.txt";
|
||||
|
||||
private String crashContent;
|
||||
private TextView crashView;
|
||||
|
||||
public boolean resetCrashLog = false;
|
||||
|
||||
public static boolean isNewCrash(File crashLog) throws Exception {
|
||||
String content = Tools.read(crashLog.getAbsolutePath());
|
||||
return crashLog != null && content.startsWith("---- Minecraft Crash Report ----");
|
||||
}
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.lmaintab_crashlog, container, false);
|
||||
public class CrashFragment extends Fragment {
|
||||
public static String LAST_CRASH_FILE = Tools.DIR_DATA + "/lastcrash.txt";
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle b)
|
||||
{
|
||||
super.onActivityCreated(b);
|
||||
|
||||
crashView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogCrashTextView);
|
||||
crashView.setTypeface(Typeface.MONOSPACE);
|
||||
crashView.setHint(this.getText(R.string.main_nocrash));
|
||||
private TextView mCrashView;
|
||||
public boolean mResetCrashLog = false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.inflate(R.layout.fragment_crash_log, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mCrashView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogCrashTextView);
|
||||
mCrashView.setTypeface(Typeface.MONOSPACE);
|
||||
mCrashView.setHint(this.getText(R.string.main_nocrash));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
refreshCrashFile();
|
||||
}
|
||||
|
||||
public void refreshCrashFile()
|
||||
{
|
||||
|
||||
private void refreshCrashFile() {
|
||||
// Default text
|
||||
mCrashView.setText("");
|
||||
setLastCrash("");
|
||||
|
||||
if(mResetCrashLog) return;
|
||||
|
||||
File crashLog = Tools.lastFileModified(Tools.DIR_HOME_CRASH);
|
||||
String lastCrash = getLastCrash();
|
||||
String crashContent;
|
||||
try {
|
||||
if(!resetCrashLog){
|
||||
File crashLog = Tools.lastFileModified(Tools.DIR_HOME_CRASH);
|
||||
String lastCrash = getLastCrash();
|
||||
if (isNewCrash(crashLog)) {
|
||||
crashContent = Tools.read(crashLog.getAbsolutePath());
|
||||
Tools.write(crashLog.getAbsolutePath(), "\n" + crashContent);
|
||||
setLastCrash(crashLog.getAbsolutePath());
|
||||
crashView.setText(crashContent);
|
||||
} else if(!lastCrash.isEmpty()) {
|
||||
crashContent = Tools.read(lastCrash);
|
||||
crashView.setText(crashContent);
|
||||
} else throw new Exception();
|
||||
} else throw new Exception();
|
||||
} catch (Exception e) {
|
||||
// Can't find crash or no NEW crashes
|
||||
crashView.setText(""/*Log.getStackTraceString(e)*/);
|
||||
setLastCrash("");
|
||||
if (isNewCrash(crashLog)) {
|
||||
crashContent = Tools.read(crashLog.getAbsolutePath());
|
||||
Tools.write(crashLog.getAbsolutePath(), "\n" + crashContent);
|
||||
setLastCrash(crashLog.getAbsolutePath());
|
||||
mCrashView.setText(crashContent);
|
||||
} else if(!lastCrash.isEmpty()) {
|
||||
crashContent = Tools.read(lastCrash);
|
||||
mCrashView.setText(crashContent);
|
||||
}
|
||||
}catch (IOException ioException){
|
||||
Log.e("CrashFragment", ioException.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void setLastCrash(String newValue) {
|
||||
|
||||
private static boolean isNewCrash(File crashLog) throws IOException {
|
||||
String content = Tools.read(crashLog.getAbsolutePath());
|
||||
return crashLog != null && content.startsWith("---- Minecraft Crash Report ----");
|
||||
}
|
||||
|
||||
private void setLastCrash(String newValue) {
|
||||
try {
|
||||
Tools.write(lastCrashFile, newValue);
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
Tools.write(LAST_CRASH_FILE, newValue);
|
||||
} catch (IOException ioException) {
|
||||
throw new RuntimeException(ioException);
|
||||
}
|
||||
}
|
||||
|
||||
public String getLastCrash() {
|
||||
|
||||
private String getLastCrash() {
|
||||
try {
|
||||
return Tools.read(lastCrashFile);
|
||||
} catch (Throwable th) {
|
||||
return Tools.read(LAST_CRASH_FILE);
|
||||
} catch (IOException ioException) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -25,74 +25,45 @@ import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public class LauncherFragment extends Fragment
|
||||
{
|
||||
private WebView webNews;
|
||||
private View view;
|
||||
private Thread validUrlSelectorThread;
|
||||
private String validChangelog = "/changelog.html";
|
||||
private Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
private boolean interruptLoad = false;
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
view = inflater.inflate(R.layout.lmaintab_news, container, false);
|
||||
return view;
|
||||
}
|
||||
public void selectValidUrl() {
|
||||
String lang = LauncherPreferences.PREF_LANGUAGE;
|
||||
if(lang.equals("default")) lang = Locale.getDefault().getLanguage();
|
||||
final String localizedUrl = "/changelog-"+lang+".html";
|
||||
if(!tryUrl(Tools.URL_HOME+localizedUrl)) return;
|
||||
else {
|
||||
mainHandler.post(()->{
|
||||
interruptLoad = true;
|
||||
validChangelog = localizedUrl;
|
||||
webNews.loadUrl(Tools.URL_HOME+validChangelog);
|
||||
});
|
||||
}
|
||||
}
|
||||
public boolean tryUrl(String url) {
|
||||
Log.i("ChangelogLocale","Trying localized url: "+url);
|
||||
try {
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.connect();
|
||||
Log.i("ChangelogLocale","Code: "+conn.getResponseCode());
|
||||
return ("" + conn.getResponseCode()).startsWith("2");
|
||||
}catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public class LauncherFragment extends Fragment {
|
||||
|
||||
private WebView mNewsWebview;
|
||||
private View mRootView;
|
||||
private Thread mValidUrlSelectorThread;
|
||||
private String mValidChangelog = "/changelog.html";
|
||||
private boolean mInterruptLoad = false;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle p1)
|
||||
{
|
||||
super.onActivityCreated(p1);
|
||||
mainHandler = new Handler(Looper.myLooper());
|
||||
webNews = (WebView) getView().findViewById(R.id.lmaintabnewsNewsView);
|
||||
webNews.setWebViewClient(new WebViewClient(){
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
mRootView = inflater.inflate(R.layout.fragment_news, container, false);
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
mNewsWebview = (WebView) getView().findViewById(R.id.lmaintabnewsNewsView);
|
||||
mNewsWebview.setWebViewClient(new WebViewClient(){
|
||||
|
||||
// API < 23
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
Log.i("WebNews",failingUrl + ": "+description);
|
||||
if(webNews != null){
|
||||
if(validUrlSelectorThread.isAlive()) validUrlSelectorThread.interrupt();
|
||||
removeWebView();
|
||||
//Change the background to match the other pages.
|
||||
//We change it only when the webView is removed to avoid huge overdraw.
|
||||
LauncherFragment.this.view.setBackgroundColor(Color.parseColor("#44000000"));
|
||||
}
|
||||
if(mNewsWebview == null) return;
|
||||
|
||||
if(mValidUrlSelectorThread.isAlive()) mValidUrlSelectorThread.interrupt();
|
||||
removeWebView();
|
||||
//Change the background to match the other pages.
|
||||
//We change it only when the webView is removed to avoid huge overdraw.
|
||||
LauncherFragment.this.mRootView.setBackgroundColor(Color.parseColor("#44000000"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if(!url.equals(Tools.URL_HOME + validChangelog)){
|
||||
if(!url.equals(Tools.URL_HOME + mValidChangelog)){
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(i);
|
||||
return true;
|
||||
@@ -104,17 +75,17 @@ public class LauncherFragment extends Fragment
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
Log.i("WebNews",error.getDescription()+"");
|
||||
if(webNews != null){
|
||||
if(validUrlSelectorThread.isAlive()) validUrlSelectorThread.interrupt();
|
||||
removeWebView();
|
||||
LauncherFragment.this.view.setBackgroundColor(Color.parseColor("#44000000"));
|
||||
}
|
||||
if(mNewsWebview == null) return;
|
||||
|
||||
if(mValidUrlSelectorThread.isAlive()) mValidUrlSelectorThread.interrupt();
|
||||
removeWebView();
|
||||
LauncherFragment.this.mRootView.setBackgroundColor(Color.parseColor("#44000000"));
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
if(!request.getUrl().toString().equals(Tools.URL_HOME + validChangelog)){
|
||||
if(!request.getUrl().toString().equals(Tools.URL_HOME + mValidChangelog)){
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, request.getUrl());
|
||||
startActivity(i);
|
||||
return true;
|
||||
@@ -122,36 +93,64 @@ public class LauncherFragment extends Fragment
|
||||
return false;
|
||||
}
|
||||
});
|
||||
webNews.clearCache(true);
|
||||
webNews.getSettings().setJavaScriptEnabled(true);
|
||||
validUrlSelectorThread = new Thread(this::selectValidUrl);
|
||||
validUrlSelectorThread.start();
|
||||
if(!interruptLoad)webNews.loadUrl(Tools.URL_HOME + validChangelog);
|
||||
|
||||
mNewsWebview.clearCache(true);
|
||||
mNewsWebview.getSettings().setJavaScriptEnabled(true);
|
||||
mValidUrlSelectorThread = new Thread(this::selectValidUrl);
|
||||
mValidUrlSelectorThread.start();
|
||||
if(!mInterruptLoad) mNewsWebview.loadUrl(Tools.URL_HOME + mValidChangelog);
|
||||
}
|
||||
|
||||
private void selectValidUrl() {
|
||||
String lang = LauncherPreferences.PREF_LANGUAGE;
|
||||
if(lang.equals("default")) lang = Locale.getDefault().getLanguage();
|
||||
final String localizedUrl = "/changelog-" + lang + ".html";
|
||||
|
||||
if(!tryUrl(Tools.URL_HOME+localizedUrl)) return;
|
||||
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
mInterruptLoad = true;
|
||||
mValidChangelog = localizedUrl;
|
||||
mNewsWebview.loadUrl(Tools.URL_HOME + mValidChangelog);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean tryUrl(String url) {
|
||||
Log.i("ChangelogLocale","Trying localized url: "+url);
|
||||
try {
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.connect();
|
||||
Log.i("ChangelogLocale","Code: "+conn.getResponseCode());
|
||||
return ("" + conn.getResponseCode()).startsWith("2");
|
||||
}catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeWebView() {
|
||||
//Removing the parent which contain the webView crashes the viewPager.
|
||||
//So I just try to "minimize" its impact on memory instead
|
||||
|
||||
webNews.clearHistory();
|
||||
webNews.clearCache(true);
|
||||
mNewsWebview.clearHistory();
|
||||
mNewsWebview.clearCache(true);
|
||||
|
||||
// Loading a blank page is optional, but will ensure that the WebView isn't doing anything when you destroy it.
|
||||
webNews.loadUrl("about:blank");
|
||||
mNewsWebview.loadUrl("about:blank");
|
||||
|
||||
webNews.onPause();
|
||||
webNews.removeAllViews();
|
||||
webNews.destroyDrawingCache();
|
||||
mNewsWebview.onPause();
|
||||
mNewsWebview.removeAllViews();
|
||||
mNewsWebview.destroyDrawingCache();
|
||||
|
||||
// make sure to call webNews.resumeTimers().
|
||||
webNews.pauseTimers();
|
||||
mNewsWebview.pauseTimers();
|
||||
|
||||
webNews.setVisibility(View.GONE);
|
||||
mNewsWebview.setVisibility(View.GONE);
|
||||
|
||||
webNews.destroy();
|
||||
mNewsWebview.destroy();
|
||||
|
||||
// Null out the reference so that you don't end up re-using it.
|
||||
webNews = null;
|
||||
mNewsWebview = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,31 +14,33 @@ import net.kdt.pojavlaunch.R;
|
||||
public class MultiRTConfigDialog {
|
||||
public static final int MULTIRT_PICK_RUNTIME = 2048;
|
||||
public static final int MULTIRT_PICK_RUNTIME_STARTUP = 2049;
|
||||
public AlertDialog dialog;
|
||||
public RecyclerView dialogView;
|
||||
public void prepare(BaseLauncherActivity ctx) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||
public AlertDialog mDialog;
|
||||
public RecyclerView mDialogView;
|
||||
|
||||
public void prepare(BaseLauncherActivity activity) {
|
||||
mDialogView = new RecyclerView(activity);
|
||||
mDialogView.setLayoutManager(new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false));
|
||||
mDialogView.setAdapter(new RTRecyclerViewAdapter(this));
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(R.string.multirt_config_title);
|
||||
dialogView = new RecyclerView(ctx);
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
|
||||
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
dialogView.setLayoutManager(linearLayoutManager);
|
||||
dialogView.setAdapter(new RTRecyclerViewAdapter(this));
|
||||
builder.setView(dialogView);
|
||||
builder.setPositiveButton(R.string.multirt_config_add, (dialog, which) -> openRuntimeSelector(ctx,MULTIRT_PICK_RUNTIME));
|
||||
builder.setView(mDialogView);
|
||||
builder.setPositiveButton(R.string.multirt_config_add, (dialog, which) -> openRuntimeSelector(activity,MULTIRT_PICK_RUNTIME));
|
||||
builder.setNegativeButton(R.string.mcn_exit_call, (dialog, which) -> dialog.cancel());
|
||||
dialog = builder.create();
|
||||
mDialog = builder.create();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
RecyclerView.Adapter adapter = dialogView.getAdapter();
|
||||
if(adapter != null)dialogView.getAdapter().notifyDataSetChanged();
|
||||
RecyclerView.Adapter adapter = mDialogView.getAdapter();
|
||||
if(adapter != null) mDialogView.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
public static void openRuntimeSelector(Activity ctx, int code) {
|
||||
|
||||
public static void openRuntimeSelector(Activity activity, int code) {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("xz");
|
||||
if(mimeType == null) mimeType = "*/*";
|
||||
intent.setType(mimeType);
|
||||
ctx.startActivityForResult(intent,code);
|
||||
activity.startActivityForResult(intent,code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.kdt.pojavlaunch.multirt;
|
||||
|
||||
import android.content.Context;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
@@ -22,135 +23,102 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MultiRTUtils {
|
||||
public static HashMap<String,Runtime> cache = new HashMap<>();
|
||||
public static class Runtime {
|
||||
public Runtime(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String name;
|
||||
public String versionString;
|
||||
public String arch;
|
||||
public int javaVersion;
|
||||
public interface RuntimeProgressReporter {
|
||||
void reportStringProgress(int resId, Object ... stuff);
|
||||
}
|
||||
|
||||
private static final HashMap<String,Runtime> sCache = new HashMap<>();
|
||||
|
||||
private static final File RUNTIME_FOLDER = new File(Tools.MULTIRT_HOME);
|
||||
private static final String JAVA_VERSION_STR = "JAVA_VERSION=\"";
|
||||
private static final String OS_ARCH_STR = "OS_ARCH=\"";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Runtime runtime = (Runtime) o;
|
||||
return name.equals(runtime.name);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
public static interface ProgressReporterThingy {
|
||||
void reportStringProgress(int resid, Object ... stuff);
|
||||
}
|
||||
private static final File runtimeFolder = new File(Tools.MULTIRT_HOME);
|
||||
private static final String JAVA_VERSION_str = "JAVA_VERSION=\"";
|
||||
private static final String OS_ARCH_str = "OS_ARCH=\"";
|
||||
public static List<Runtime> getRuntimes() {
|
||||
if(!runtimeFolder.exists()) runtimeFolder.mkdirs();
|
||||
ArrayList<Runtime> ret = new ArrayList<>();
|
||||
if(!RUNTIME_FOLDER.exists()) RUNTIME_FOLDER.mkdirs();
|
||||
|
||||
ArrayList<Runtime> runtimes = new ArrayList<>();
|
||||
System.out.println("Fetch runtime list");
|
||||
for(File f : runtimeFolder.listFiles()) {
|
||||
ret.add(read(f.getName()));
|
||||
for(File f : RUNTIME_FOLDER.listFiles()) {
|
||||
runtimes.add(read(f.getName()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
return runtimes;
|
||||
}
|
||||
public static String getExactJREName(int majorVersion) {
|
||||
|
||||
public static String getExactJreName(int majorVersion) {
|
||||
List<Runtime> runtimes = getRuntimes();
|
||||
for(Runtime r : runtimes) {
|
||||
if(r.javaVersion == majorVersion) {
|
||||
return r.name;
|
||||
}
|
||||
}
|
||||
for(Runtime r : runtimes)
|
||||
if(r.javaVersion == majorVersion)return r.name;
|
||||
|
||||
return null;
|
||||
}
|
||||
public static String getNearestJREName(int majorVersion) {
|
||||
|
||||
public static String getNearestJreName(int majorVersion) {
|
||||
List<Runtime> runtimes = getRuntimes();
|
||||
int diff_factor = Integer.MAX_VALUE;
|
||||
String result = null;
|
||||
for(Runtime r : runtimes) {
|
||||
if(r.javaVersion >= majorVersion) { // lower - not useful
|
||||
int currentFactor = r.javaVersion - majorVersion;
|
||||
if(diff_factor > currentFactor) {
|
||||
result = r.name;
|
||||
diff_factor = currentFactor;
|
||||
}
|
||||
if(r.javaVersion < majorVersion) continue; // lower - not useful
|
||||
|
||||
int currentFactor = r.javaVersion - majorVersion;
|
||||
if(diff_factor > currentFactor) {
|
||||
result = r.name;
|
||||
diff_factor = currentFactor;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public static void installRuntimeNamed(InputStream runtimeInputStream, String name, ProgressReporterThingy thingy) throws IOException {
|
||||
File dest = new File(runtimeFolder,"/"+name);
|
||||
|
||||
public static void installRuntimeNamed(InputStream runtimeInputStream, String name, RuntimeProgressReporter progressReporter) throws IOException {
|
||||
File dest = new File(RUNTIME_FOLDER,"/"+name);
|
||||
File tmp = new File(dest,"temporary");
|
||||
if(dest.exists()) FileUtils.deleteDirectory(dest);
|
||||
dest.mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(tmp);
|
||||
thingy.reportStringProgress(R.string.multirt_progress_caching);
|
||||
progressReporter.reportStringProgress(R.string.multirt_progress_caching);
|
||||
IOUtils.copy(runtimeInputStream,fos);
|
||||
fos.close();
|
||||
runtimeInputStream.close();
|
||||
uncompressTarXZ(tmp,dest,thingy);
|
||||
uncompressTarXZ(tmp,dest,progressReporter);
|
||||
tmp.delete();
|
||||
read(name);
|
||||
}
|
||||
private static void __installRuntimeNamed__NoRM(InputStream runtimeInputStream, File dest, ProgressReporterThingy thingy) throws IOException {
|
||||
File tmp = new File(dest,"temporary");
|
||||
FileOutputStream fos = new FileOutputStream(tmp);
|
||||
thingy.reportStringProgress(R.string.multirt_progress_caching);
|
||||
IOUtils.copy(runtimeInputStream,fos);
|
||||
fos.close();
|
||||
runtimeInputStream.close();
|
||||
uncompressTarXZ(tmp,dest,thingy);
|
||||
tmp.delete();
|
||||
}
|
||||
|
||||
public static void postPrepare(Context ctx, String name) throws IOException {
|
||||
File dest = new File(runtimeFolder,"/"+name);
|
||||
File dest = new File(RUNTIME_FOLDER,"/" + name);
|
||||
if(!dest.exists()) return;
|
||||
Runtime r = read(name);
|
||||
Runtime runtime = read(name);
|
||||
String libFolder = "lib";
|
||||
if(new File(dest,libFolder+"/"+r.arch).exists()) libFolder = libFolder+"/"+r.arch;
|
||||
File ftIn = new File(dest, libFolder+ "/libfreetype.so.6");
|
||||
if(new File(dest,libFolder + "/" + runtime.arch).exists()) libFolder = libFolder + "/" + runtime.arch;
|
||||
File ftIn = new File(dest, libFolder + "/libfreetype.so.6");
|
||||
File ftOut = new File(dest, libFolder + "/libfreetype.so");
|
||||
if (ftIn.exists() && (!ftOut.exists() || ftIn.length() != ftOut.length())) {
|
||||
ftIn.renameTo(ftOut);
|
||||
}
|
||||
|
||||
// Refresh libraries
|
||||
copyDummyNativeLib(ctx,"libawt_xawt.so",dest,libFolder);
|
||||
copyDummyNativeLib(ctx,"libawt_xawt.so", dest, libFolder);
|
||||
}
|
||||
private static void copyDummyNativeLib(Context ctx, String name, File dest, String libFolder) throws IOException {
|
||||
|
||||
File fileLib = new File(dest, "/"+libFolder + "/" + name);
|
||||
fileLib.delete();
|
||||
FileInputStream is = new FileInputStream(new File(ctx.getApplicationInfo().nativeLibraryDir, name));
|
||||
FileOutputStream os = new FileOutputStream(fileLib);
|
||||
IOUtils.copy(is, os);
|
||||
is.close();
|
||||
os.close();
|
||||
}
|
||||
public static Runtime installRuntimeNamedBinpack(InputStream universalFileInputStream, InputStream platformBinsInputStream, String name, String binpackVersion, ProgressReporterThingy thingy) throws IOException {
|
||||
File dest = new File(runtimeFolder,"/"+name);
|
||||
public static Runtime installRuntimeNamedBinpack(InputStream universalFileInputStream, InputStream platformBinsInputStream, String name, String binpackVersion, RuntimeProgressReporter thingy) throws IOException {
|
||||
File dest = new File(RUNTIME_FOLDER,"/"+name);
|
||||
if(dest.exists()) FileUtils.deleteDirectory(dest);
|
||||
dest.mkdirs();
|
||||
__installRuntimeNamed__NoRM(universalFileInputStream,dest,thingy);
|
||||
__installRuntimeNamed__NoRM(platformBinsInputStream,dest,thingy);
|
||||
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
|
||||
installRuntimeNamedNoRemove(universalFileInputStream,dest,thingy);
|
||||
installRuntimeNamedNoRemove(platformBinsInputStream,dest,thingy);
|
||||
File binpack_verfile = new File(RUNTIME_FOLDER,"/"+name+"/pojav_version");
|
||||
FileOutputStream fos = new FileOutputStream(binpack_verfile);
|
||||
fos.write(binpackVersion.getBytes());
|
||||
fos.close();
|
||||
cache.remove(name); // Force reread
|
||||
sCache.remove(name); // Force reread
|
||||
return read(name);
|
||||
}
|
||||
|
||||
public static String __internal__readBinpackVersion(String name) {
|
||||
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
|
||||
File binpack_verfile = new File(RUNTIME_FOLDER,"/"+name+"/pojav_version");
|
||||
try {
|
||||
if (binpack_verfile.exists()) {
|
||||
return Tools.read(binpack_verfile.getAbsolutePath());
|
||||
@@ -162,38 +130,42 @@ public class MultiRTUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeRuntimeNamed(String name) throws IOException {
|
||||
File dest = new File(runtimeFolder,"/"+name);
|
||||
File dest = new File(RUNTIME_FOLDER,"/"+name);
|
||||
if(dest.exists()) {
|
||||
FileUtils.deleteDirectory(dest);
|
||||
cache.remove(name);
|
||||
sCache.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setRuntimeNamed(Context ctx, String name) throws IOException {
|
||||
File dest = new File(runtimeFolder,"/"+name);
|
||||
File dest = new File(RUNTIME_FOLDER,"/"+name);
|
||||
if((!dest.exists()) || MultiRTUtils.forceReread(name).versionString == null) throw new RuntimeException("Selected runtime is broken!");
|
||||
Tools.DIR_HOME_JRE = dest.getAbsolutePath();
|
||||
JREUtils.relocateLibPath(ctx);
|
||||
}
|
||||
|
||||
public static Runtime forceReread(String name) {
|
||||
cache.remove(name);
|
||||
sCache.remove(name);
|
||||
return read(name);
|
||||
}
|
||||
|
||||
public static Runtime read(String name) {
|
||||
if(cache.containsKey(name)) return cache.get(name);
|
||||
Runtime retur;
|
||||
File release = new File(runtimeFolder,"/"+name+"/release");
|
||||
if(sCache.containsKey(name)) return sCache.get(name);
|
||||
Runtime returnRuntime;
|
||||
File release = new File(RUNTIME_FOLDER,"/"+name+"/release");
|
||||
if(!release.exists()) {
|
||||
return new Runtime(name);
|
||||
}
|
||||
try {
|
||||
String content = Tools.read(release.getAbsolutePath());
|
||||
int _JAVA_VERSION_index = content.indexOf(JAVA_VERSION_str);
|
||||
int _OS_ARCH_index = content.indexOf(OS_ARCH_str);
|
||||
if(_JAVA_VERSION_index != -1 && _OS_ARCH_index != -1) {
|
||||
_JAVA_VERSION_index += JAVA_VERSION_str.length();
|
||||
_OS_ARCH_index += OS_ARCH_str.length();
|
||||
String javaVersion = content.substring(_JAVA_VERSION_index,content.indexOf('"',_JAVA_VERSION_index));
|
||||
int javaVersionIndex = content.indexOf(JAVA_VERSION_STR);
|
||||
int osArchIndex = content.indexOf(OS_ARCH_STR);
|
||||
if(javaVersionIndex != -1 && osArchIndex != -1) {
|
||||
javaVersionIndex += JAVA_VERSION_STR.length();
|
||||
osArchIndex += OS_ARCH_STR.length();
|
||||
String javaVersion = content.substring(javaVersionIndex,content.indexOf('"', javaVersionIndex));
|
||||
String[] javaVersionSplit = javaVersion.split("\\.");
|
||||
int javaVersionInt;
|
||||
if (javaVersionSplit[0].equals("1")) {
|
||||
@@ -201,25 +173,46 @@ public class MultiRTUtils {
|
||||
} else {
|
||||
javaVersionInt = Integer.parseInt(javaVersionSplit[0]);
|
||||
}
|
||||
Runtime r = new Runtime(name);
|
||||
r.arch = content.substring(_OS_ARCH_index,content.indexOf('"',_OS_ARCH_index));
|
||||
r.javaVersion = javaVersionInt;
|
||||
r.versionString = javaVersion;
|
||||
retur = r;
|
||||
Runtime runtime = new Runtime(name);
|
||||
runtime.arch = content.substring(osArchIndex,content.indexOf('"', osArchIndex));
|
||||
runtime.javaVersion = javaVersionInt;
|
||||
runtime.versionString = javaVersion;
|
||||
returnRuntime = runtime;
|
||||
}else{
|
||||
retur = new Runtime(name);
|
||||
returnRuntime = new Runtime(name);
|
||||
}
|
||||
}catch(IOException e) {
|
||||
retur = new Runtime(name);
|
||||
returnRuntime = new Runtime(name);
|
||||
}
|
||||
cache.put(name,retur);
|
||||
return retur;
|
||||
sCache.put(name, returnRuntime);
|
||||
return returnRuntime;
|
||||
}
|
||||
private static void uncompressTarXZ(final File tarFile, final File dest, final ProgressReporterThingy thingy) throws IOException {
|
||||
dest.mkdirs();
|
||||
TarArchiveInputStream tarIn = null;
|
||||
|
||||
tarIn = new TarArchiveInputStream(
|
||||
private static void copyDummyNativeLib(Context ctx, String name, File dest, String libFolder) throws IOException {
|
||||
File fileLib = new File(dest, "/"+libFolder + "/" + name);
|
||||
fileLib.delete();
|
||||
FileInputStream is = new FileInputStream(new File(ctx.getApplicationInfo().nativeLibraryDir, name));
|
||||
FileOutputStream os = new FileOutputStream(fileLib);
|
||||
IOUtils.copy(is, os);
|
||||
is.close();
|
||||
os.close();
|
||||
}
|
||||
|
||||
private static void installRuntimeNamedNoRemove(InputStream runtimeInputStream, File dest, RuntimeProgressReporter progressReporter) throws IOException {
|
||||
File tmp = new File(dest,"temporary");
|
||||
FileOutputStream fos = new FileOutputStream(tmp);
|
||||
progressReporter.reportStringProgress(R.string.multirt_progress_caching);
|
||||
IOUtils.copy(runtimeInputStream,fos);
|
||||
fos.close();
|
||||
runtimeInputStream.close();
|
||||
uncompressTarXZ(tmp,dest,progressReporter);
|
||||
tmp.delete();
|
||||
}
|
||||
|
||||
private static void uncompressTarXZ(final File tarFile, final File dest, final RuntimeProgressReporter thingy) throws IOException {
|
||||
dest.mkdirs();
|
||||
|
||||
TarArchiveInputStream tarIn = new TarArchiveInputStream(
|
||||
new XZCompressorInputStream(
|
||||
new BufferedInputStream(
|
||||
new FileInputStream(tarFile)
|
||||
@@ -251,7 +244,7 @@ public class MultiRTUtils {
|
||||
// Libcore one support all Android versions
|
||||
Os.symlink(tarEntry.getName(), tarEntry.getLinkName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Log.e("MultiRT", e.toString());
|
||||
}
|
||||
|
||||
} else if (tarEntry.isDirectory()) {
|
||||
|
||||
@@ -23,115 +23,126 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class RTRecyclerViewAdapter extends RecyclerView.Adapter<RTRecyclerViewAdapter.RTViewHolder> {
|
||||
MultiRTConfigDialog dialog;
|
||||
|
||||
MultiRTConfigDialog mConfigDialog;
|
||||
public RTRecyclerViewAdapter(MultiRTConfigDialog dialog) {
|
||||
this.dialog = dialog;
|
||||
this.mConfigDialog = dialog;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RTViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View recyclableView = LayoutInflater.from(parent.getContext()).inflate(R.layout.multirt_recyclable_view,parent,false);
|
||||
View recyclableView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_multirt_runtime,parent,false);
|
||||
return new RTViewHolder(recyclableView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RTViewHolder holder, int position) {
|
||||
final List<MultiRTUtils.Runtime> runtimes = MultiRTUtils.getRuntimes();
|
||||
final List<Runtime> runtimes = MultiRTUtils.getRuntimes();
|
||||
holder.bindRuntime(runtimes.get(position),position);
|
||||
}
|
||||
public boolean isDefaultRuntime(MultiRTUtils.Runtime rt) {
|
||||
return LauncherPreferences.PREF_DEFAULT_RUNTIME.equals(rt.name);
|
||||
}
|
||||
public void setDefault(MultiRTUtils.Runtime rt){
|
||||
LauncherPreferences.PREF_DEFAULT_RUNTIME = rt.name;
|
||||
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
|
||||
RTRecyclerViewAdapter.this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return MultiRTUtils.getRuntimes().size();
|
||||
}
|
||||
|
||||
public boolean isDefaultRuntime(Runtime rt) {
|
||||
return LauncherPreferences.PREF_DEFAULT_RUNTIME.equals(rt.name);
|
||||
}
|
||||
|
||||
public void setDefault(Runtime rt){
|
||||
LauncherPreferences.PREF_DEFAULT_RUNTIME = rt.name;
|
||||
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
|
||||
RTRecyclerViewAdapter.this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
public class RTViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
|
||||
final TextView javaVersionView;
|
||||
final TextView fullJavaVersionView;
|
||||
final ColorStateList defaultColors;
|
||||
final Button setDefaultButton;
|
||||
final Context ctx;
|
||||
MultiRTUtils.Runtime currentRuntime;
|
||||
int currentPosition;
|
||||
final TextView mJavaVersionTextView;
|
||||
final TextView mFullJavaVersionTextView;
|
||||
final ColorStateList mDefaultColors;
|
||||
final Button mSetDefaultButton;
|
||||
final Context mContext;
|
||||
Runtime mCurrentRuntime;
|
||||
int mCurrentPosition;
|
||||
|
||||
public RTViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
javaVersionView = itemView.findViewById(R.id.multirt_view_java_version);
|
||||
fullJavaVersionView = itemView.findViewById(R.id.multirt_view_java_version_full);
|
||||
mJavaVersionTextView = itemView.findViewById(R.id.multirt_view_java_version);
|
||||
mFullJavaVersionTextView = itemView.findViewById(R.id.multirt_view_java_version_full);
|
||||
mSetDefaultButton = itemView.findViewById(R.id.multirt_view_setdefaultbtn);
|
||||
mSetDefaultButton.setOnClickListener(this);
|
||||
mDefaultColors = mFullJavaVersionTextView.getTextColors();
|
||||
mContext = itemView.getContext();
|
||||
itemView.findViewById(R.id.multirt_view_removebtn).setOnClickListener(this);
|
||||
setDefaultButton = itemView.findViewById(R.id.multirt_view_setdefaultbtn);
|
||||
setDefaultButton.setOnClickListener(this);
|
||||
defaultColors = fullJavaVersionView.getTextColors();
|
||||
ctx = itemView.getContext();
|
||||
}
|
||||
public void bindRuntime(MultiRTUtils.Runtime rt, int pos) {
|
||||
currentRuntime = rt;
|
||||
currentPosition = pos;
|
||||
if(rt.versionString != null && Tools.DEVICE_ARCHITECTURE == Architecture.archAsInt(rt.arch)) {
|
||||
javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion));
|
||||
fullJavaVersionView.setText(rt.versionString);
|
||||
fullJavaVersionView.setTextColor(defaultColors);
|
||||
setDefaultButton.setVisibility(View.VISIBLE);
|
||||
boolean default_ = isDefaultRuntime(rt);
|
||||
setDefaultButton.setEnabled(!default_);
|
||||
setDefaultButton.setText(default_?R.string.multirt_config_setdefault_already:R.string.multirt_config_setdefault);
|
||||
}else{
|
||||
if(rt.versionString == null){
|
||||
fullJavaVersionView.setText(R.string.multirt_runtime_corrupt);
|
||||
}else{
|
||||
fullJavaVersionView.setText(ctx.getString(R.string.multirt_runtime_incompatiblearch, rt.arch));
|
||||
}
|
||||
javaVersionView.setText(rt.name);
|
||||
fullJavaVersionView.setTextColor(Color.RED);
|
||||
setDefaultButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(v.getId() == R.id.multirt_view_removebtn) {
|
||||
if (currentRuntime != null) {
|
||||
if(MultiRTUtils.getRuntimes().size() < 2 && setDefaultButton.isShown()) {
|
||||
AlertDialog.Builder bldr = new AlertDialog.Builder(ctx);
|
||||
bldr.setTitle(R.string.global_error);
|
||||
bldr.setMessage(R.string.multirt_config_removeerror_last);
|
||||
bldr.setPositiveButton(android.R.string.ok,(adapter, which)->adapter.dismiss());
|
||||
bldr.show();
|
||||
return;
|
||||
}
|
||||
public void onClick(View view) {
|
||||
if(view.getId() == R.id.multirt_view_removebtn) {
|
||||
if (mCurrentRuntime == null) return;
|
||||
|
||||
final ProgressDialog barrier = new ProgressDialog(ctx);
|
||||
barrier.setMessage(ctx.getString(R.string.global_waiting));
|
||||
barrier.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
barrier.setCancelable(false);
|
||||
barrier.show();
|
||||
Thread t = new Thread(() -> {
|
||||
try {
|
||||
MultiRTUtils.removeRuntimeNamed(currentRuntime.name);
|
||||
} catch (IOException e) {
|
||||
Tools.showError(itemView.getContext(), e);
|
||||
}
|
||||
v.post(() -> {
|
||||
if(isDefaultRuntime(currentRuntime)) setDefault(MultiRTUtils.getRuntimes().get(0));
|
||||
barrier.dismiss();
|
||||
RTRecyclerViewAdapter.this.notifyDataSetChanged();
|
||||
dialog.dialog.show();
|
||||
});
|
||||
});
|
||||
t.start();
|
||||
if(MultiRTUtils.getRuntimes().size() < 2 && mSetDefaultButton.isShown()) {
|
||||
AlertDialog.Builder bldr = new AlertDialog.Builder(mContext);
|
||||
bldr.setTitle(R.string.global_error);
|
||||
bldr.setMessage(R.string.multirt_config_removeerror_last);
|
||||
bldr.setPositiveButton(android.R.string.ok,(adapter, which)->adapter.dismiss());
|
||||
bldr.show();
|
||||
return;
|
||||
}
|
||||
}else if(v.getId() == R.id.multirt_view_setdefaultbtn) {
|
||||
if(currentRuntime != null) {
|
||||
setDefault(currentRuntime);
|
||||
|
||||
final ProgressDialog barrier = new ProgressDialog(mContext);
|
||||
barrier.setMessage(mContext.getString(R.string.global_waiting));
|
||||
barrier.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
barrier.setCancelable(false);
|
||||
barrier.show();
|
||||
Thread t = new Thread(() -> {
|
||||
try {
|
||||
MultiRTUtils.removeRuntimeNamed(mCurrentRuntime.name);
|
||||
} catch (IOException e) {
|
||||
Tools.showError(itemView.getContext(), e);
|
||||
}
|
||||
view.post(() -> {
|
||||
if(isDefaultRuntime(mCurrentRuntime)) setDefault(MultiRTUtils.getRuntimes().get(0));
|
||||
barrier.dismiss();
|
||||
RTRecyclerViewAdapter.this.notifyDataSetChanged();
|
||||
mConfigDialog.mDialog.show();
|
||||
});
|
||||
});
|
||||
t.start();
|
||||
|
||||
}else if(view.getId() == R.id.multirt_view_setdefaultbtn) {
|
||||
if(mCurrentRuntime != null) {
|
||||
setDefault(mCurrentRuntime);
|
||||
RTRecyclerViewAdapter.this.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void bindRuntime(Runtime runtime, int pos) {
|
||||
mCurrentRuntime = runtime;
|
||||
mCurrentPosition = pos;
|
||||
if(runtime.versionString != null && Tools.DEVICE_ARCHITECTURE == Architecture.archAsInt(runtime.arch)) {
|
||||
mJavaVersionTextView.setText(mContext.getString(R.string.multirt_java_ver, runtime.name, runtime.javaVersion));
|
||||
mFullJavaVersionTextView.setText(runtime.versionString);
|
||||
mFullJavaVersionTextView.setTextColor(mDefaultColors);
|
||||
mSetDefaultButton.setVisibility(View.VISIBLE);
|
||||
boolean defaultRuntime = isDefaultRuntime(runtime);
|
||||
mSetDefaultButton.setEnabled(!defaultRuntime);
|
||||
mSetDefaultButton.setText(defaultRuntime ? R.string.multirt_config_setdefault_already:R.string.multirt_config_setdefault);
|
||||
return;
|
||||
}
|
||||
|
||||
// Problematic runtime moment
|
||||
if(runtime.versionString == null){
|
||||
mFullJavaVersionTextView.setText(R.string.multirt_runtime_corrupt);
|
||||
}else{
|
||||
mFullJavaVersionTextView.setText(mContext.getString(R.string.multirt_runtime_incompatiblearch, runtime.arch));
|
||||
}
|
||||
mJavaVersionTextView.setText(runtime.name);
|
||||
mFullJavaVersionTextView.setTextColor(Color.RED);
|
||||
mSetDefaultButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,39 +16,39 @@ import net.kdt.pojavlaunch.R;
|
||||
import java.util.List;
|
||||
|
||||
public class RTSpinnerAdapter implements SpinnerAdapter {
|
||||
final Context ctx;
|
||||
List<MultiRTUtils.Runtime> runtimes;
|
||||
public RTSpinnerAdapter(@NonNull Context context, List<MultiRTUtils.Runtime> runtimes) {
|
||||
this.runtimes = runtimes;
|
||||
MultiRTUtils.Runtime runtime = new MultiRTUtils.Runtime("<Default>");
|
||||
final Context mContext;
|
||||
List<Runtime> mRuntimes;
|
||||
public RTSpinnerAdapter(@NonNull Context context, List<Runtime> runtimes) {
|
||||
mRuntimes = runtimes;
|
||||
Runtime runtime = new Runtime("<Default>");
|
||||
runtime.versionString = "";
|
||||
this.runtimes.add(runtime);
|
||||
ctx = context;
|
||||
mRuntimes.add(runtime);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
//STUB
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
//STUB
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return runtimes.size();
|
||||
return mRuntimes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return runtimes.get(position);
|
||||
return mRuntimes.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return runtimes.get(position).name.hashCode();
|
||||
return mRuntimes.get(position).name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,25 +59,25 @@ public class RTSpinnerAdapter implements SpinnerAdapter {
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
View v = convertView!=null?
|
||||
View view = convertView != null?
|
||||
convertView:
|
||||
LayoutInflater.from(ctx).inflate(R.layout.multirt_recyclable_view,parent,false);
|
||||
LayoutInflater.from(mContext).inflate(R.layout.item_multirt_runtime,parent,false);
|
||||
|
||||
MultiRTUtils.Runtime rt = runtimes.get(position);
|
||||
Runtime runtime = mRuntimes.get(position);
|
||||
|
||||
final TextView javaVersionView = v.findViewById(R.id.multirt_view_java_version);
|
||||
final TextView fullJavaVersionView = v.findViewById(R.id.multirt_view_java_version_full);
|
||||
v.findViewById(R.id.multirt_view_removebtn).setVisibility(View.GONE);
|
||||
v.findViewById(R.id.multirt_view_setdefaultbtn).setVisibility(View.GONE);
|
||||
final TextView javaVersionView = view.findViewById(R.id.multirt_view_java_version);
|
||||
final TextView fullJavaVersionView = view.findViewById(R.id.multirt_view_java_version_full);
|
||||
view.findViewById(R.id.multirt_view_removebtn).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.multirt_view_setdefaultbtn).setVisibility(View.GONE);
|
||||
|
||||
if(rt.versionString != null) {
|
||||
javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion));
|
||||
fullJavaVersionView.setText(rt.versionString);
|
||||
if(runtime.versionString != null) {
|
||||
javaVersionView.setText(mContext.getString(R.string.multirt_java_ver, runtime.name, runtime.javaVersion));
|
||||
fullJavaVersionView.setText(runtime.versionString);
|
||||
}else{
|
||||
javaVersionView.setText(rt.name);
|
||||
javaVersionView.setText(runtime.name);
|
||||
fullJavaVersionView.setText(R.string.multirt_runtime_corrupt);
|
||||
}
|
||||
return v;
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +92,7 @@ public class RTSpinnerAdapter implements SpinnerAdapter {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return runtimes.isEmpty();
|
||||
return mRuntimes.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.kdt.pojavlaunch.multirt;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Runtime {
|
||||
public Runtime(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String name;
|
||||
public String versionString;
|
||||
public String arch;
|
||||
public int javaVersion;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Runtime runtime = (Runtime) o;
|
||||
return name.equals(runtime.name);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,7 @@ import net.kdt.pojavlaunch.R;
|
||||
/** Custom preference class displaying a dialog */
|
||||
public class ControlOffsetPreference extends Preference {
|
||||
|
||||
private AlertDialog preferenceDialog;
|
||||
|
||||
|
||||
private AlertDialog mPreferenceDialog;
|
||||
|
||||
public ControlOffsetPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -34,43 +32,19 @@ public class ControlOffsetPreference extends Preference {
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
private void init(){
|
||||
// Setup visual values
|
||||
if(getTitle() == null){
|
||||
setTitle(R.string.preference_control_offset_title);
|
||||
setSummary(R.string.preference_control_offset_description);
|
||||
}
|
||||
if(getIcon() == null){
|
||||
setIcon(android.R.drawable.radiobutton_off_background);
|
||||
}
|
||||
|
||||
// Prepare Alert dialog
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext());
|
||||
dialogBuilder.setView(R.layout.control_offset_preference_dialog);
|
||||
dialogBuilder.setTitle(getContext().getString(R.string.control_offset_title));
|
||||
|
||||
dialogBuilder.setPositiveButton(android.R.string.ok, null);
|
||||
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
preferenceDialog = dialogBuilder.create();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
preferenceDialog.show();
|
||||
mPreferenceDialog.show();
|
||||
|
||||
SeekBar topOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_top_seekbar);
|
||||
SeekBar rightOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_right_seekbar);
|
||||
SeekBar bottomOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_bottom_seekbar);
|
||||
SeekBar leftOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_left_seekbar);
|
||||
SeekBar topOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_top_seekbar);
|
||||
SeekBar rightOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_right_seekbar);
|
||||
SeekBar bottomOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_bottom_seekbar);
|
||||
SeekBar leftOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_left_seekbar);
|
||||
|
||||
TextView topOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_top_textview);
|
||||
TextView rightOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_right_textview);
|
||||
TextView bottomOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_bottom_textview);
|
||||
TextView leftOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_left_textview);
|
||||
TextView topOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_top_textview);
|
||||
TextView rightOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_right_textview);
|
||||
TextView bottomOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_bottom_textview);
|
||||
TextView leftOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_left_textview);
|
||||
|
||||
SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
@@ -118,15 +92,36 @@ public class ControlOffsetPreference extends Preference {
|
||||
seekBarChangeListener.onProgressChanged(leftOffsetSeekbar, PREF_CONTROL_LEFT_OFFSET, false);
|
||||
|
||||
// Custom writing to preferences
|
||||
preferenceDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(view -> {
|
||||
mPreferenceDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(view -> {
|
||||
DEFAULT_PREF.edit().putInt("controlTopOffset", topOffsetSeekbar.getProgress()).apply();
|
||||
DEFAULT_PREF.edit().putInt("controlRightOffset", rightOffsetSeekbar.getProgress()).apply();
|
||||
DEFAULT_PREF.edit().putInt("controlBottomOffset", bottomOffsetSeekbar.getProgress()).apply();
|
||||
DEFAULT_PREF.edit().putInt("controlLeftOffset", leftOffsetSeekbar.getProgress()).apply();
|
||||
|
||||
|
||||
preferenceDialog.dismiss();
|
||||
mPreferenceDialog.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
private void init(){
|
||||
// Setup visual values
|
||||
if(getTitle() == null){
|
||||
setTitle(R.string.preference_control_offset_title);
|
||||
setSummary(R.string.preference_control_offset_description);
|
||||
}
|
||||
if(getIcon() == null){
|
||||
setIcon(android.R.drawable.radiobutton_off_background);
|
||||
}
|
||||
|
||||
// Prepare Alert dialog
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext());
|
||||
dialogBuilder.setView(R.layout.dialog_control_offset_preference);
|
||||
dialogBuilder.setTitle(getContext().getString(R.string.control_offset_title));
|
||||
|
||||
dialogBuilder.setPositiveButton(android.R.string.ok, null);
|
||||
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
mPreferenceDialog = dialogBuilder.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ import net.kdt.pojavlaunch.R;
|
||||
public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
|
||||
/** The suffix displayed */
|
||||
private String suffix = "";
|
||||
private String mSuffix = "";
|
||||
/** Custom minimum value to provide the same behavior as the usual setMin */
|
||||
private int mMin;
|
||||
/** The textview associated by default to the preference */
|
||||
private TextView textView;
|
||||
private TextView mTextView;
|
||||
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
@@ -37,7 +37,6 @@ public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.seekBarPreferenceStyle);
|
||||
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context) {
|
||||
@@ -58,8 +57,8 @@ public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
TextView titleTextView = (TextView) view.findViewById(android.R.id.title);
|
||||
titleTextView.setTextColor(Color.WHITE);
|
||||
|
||||
textView = (TextView) view.findViewById(R.id.seekbar_value);
|
||||
textView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
|
||||
mTextView = (TextView) view.findViewById(R.id.seekbar_value);
|
||||
mTextView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
|
||||
SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
|
||||
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@@ -71,7 +70,7 @@ public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
progress = progress * getSeekBarIncrement();
|
||||
progress -= mMin;
|
||||
|
||||
textView.setText(String.valueOf(progress + mMin));
|
||||
mTextView.setText(String.valueOf(progress + mMin));
|
||||
updateTextViewWithSuffix();
|
||||
}
|
||||
|
||||
@@ -94,20 +93,12 @@ public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
updateTextViewWithSuffix();
|
||||
}
|
||||
|
||||
|
||||
private void updateTextViewWithSuffix(){
|
||||
if(!textView.getText().toString().endsWith(suffix)){
|
||||
textView.setText(String.format("%s%s", textView.getText(), suffix));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a suffix to be appended on the TextView associated to the value
|
||||
* @param suffix The suffix to append as a String
|
||||
*/
|
||||
public void setSuffix(String suffix) {
|
||||
this.suffix = suffix;
|
||||
this.mSuffix = suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,4 +110,11 @@ public class CustomSeekBarPreference extends SeekBarPreference {
|
||||
setMin(min);
|
||||
setMax(max);
|
||||
}
|
||||
|
||||
|
||||
private void updateTextViewWithSuffix(){
|
||||
if(!mTextView.getText().toString().endsWith(mSuffix)){
|
||||
mTextView.setText(String.format("%s%s", mTextView.getText(), mSuffix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,108 +13,112 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
|
||||
import net.kdt.pojavlaunch.multirt.RTSpinnerAdapter;
|
||||
import net.kdt.pojavlaunch.tasks.RefreshVersionListTask;
|
||||
import net.kdt.pojavlaunch.multirt.Runtime;
|
||||
import net.kdt.pojavlaunch.value.PerVersionConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PerVersionConfigDialog{
|
||||
final Context ctx;
|
||||
final AlertDialog dialog;
|
||||
final View v;
|
||||
List<MultiRTUtils.Runtime> runtimes;
|
||||
final Spinner javaVMSpinner;
|
||||
final Spinner rendererSpinner;
|
||||
final EditText customDirText;
|
||||
final EditText jvmArgsEditText;
|
||||
final List<String> renderNames;
|
||||
String selectedGameVersion = null;
|
||||
public PerVersionConfigDialog(Context _ctx) {
|
||||
ctx = _ctx;
|
||||
v = LayoutInflater.from(ctx).inflate(R.layout.pvc_popup,null);
|
||||
javaVMSpinner = v.findViewById(R.id.pvc_javaVm);
|
||||
rendererSpinner = v.findViewById(R.id.pvc_renderer);
|
||||
{
|
||||
List<String> renderList = new ArrayList<>();
|
||||
Collections.addAll(renderList, ctx.getResources().getStringArray(R.array.renderer));
|
||||
renderList.add("Default");
|
||||
renderNames = Arrays.asList(ctx.getResources().getStringArray(R.array.renderer_values));
|
||||
rendererSpinner.setAdapter(new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_dropdown_item,renderList));
|
||||
}
|
||||
customDirText = v.findViewById(R.id.pvc_customDir);
|
||||
jvmArgsEditText = v.findViewById(R.id.pvc_jvmArgs);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||
builder.setView(v);
|
||||
final Context mContext;
|
||||
final AlertDialog mDialog;
|
||||
final View mRootView;
|
||||
List<Runtime> mRuntimes;
|
||||
final Spinner mJvmSpinner;
|
||||
final Spinner mRendererSpinner;
|
||||
final EditText mCustomDirEditText;
|
||||
final EditText mJvmArgsEditText;
|
||||
final List<String> mRendererNames;
|
||||
String mSelectedGameVersion = null;
|
||||
|
||||
public PerVersionConfigDialog(Context ctx) {
|
||||
mContext = ctx;
|
||||
mRootView = LayoutInflater.from(mContext).inflate(R.layout.dialog_per_version_control,null);
|
||||
mJvmSpinner = mRootView.findViewById(R.id.pvc_javaVm);
|
||||
mRendererSpinner = mRootView.findViewById(R.id.pvc_renderer);
|
||||
|
||||
ArrayList<String> renderList = new ArrayList<>(5);
|
||||
Collections.addAll(renderList, mContext.getResources().getStringArray(R.array.renderer));
|
||||
renderList.add("Default");
|
||||
mRendererNames = Arrays.asList(mContext.getResources().getStringArray(R.array.renderer_values));
|
||||
mRendererSpinner.setAdapter(new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_dropdown_item, renderList));
|
||||
|
||||
mCustomDirEditText = mRootView.findViewById(R.id.pvc_customDir);
|
||||
mJvmArgsEditText = mRootView.findViewById(R.id.pvc_jvmArgs);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
builder.setView(mRootView);
|
||||
builder.setTitle(R.string.pvc_title);
|
||||
builder.setNegativeButton(android.R.string.cancel,(dialogInterface,i)->dialogInterface.dismiss());
|
||||
builder.setPositiveButton(android.R.string.ok,this::save);
|
||||
dialog = builder.create();
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.setPositiveButton(android.R.string.ok, this::save);
|
||||
mDialog = builder.create();
|
||||
}
|
||||
|
||||
public void refreshRuntimes() {
|
||||
if(runtimes!=null)runtimes.clear();
|
||||
runtimes = MultiRTUtils.getRuntimes();
|
||||
//runtimes.add(new MultiRTUtils.Runtime("<Default>"));
|
||||
if(mRuntimes !=null) mRuntimes.clear();
|
||||
mRuntimes = MultiRTUtils.getRuntimes();
|
||||
//runtimes.add(new Runtime("<Default>"));
|
||||
}
|
||||
private void save(DialogInterface i, int which) {
|
||||
if(selectedGameVersion == null) {
|
||||
i.dismiss();
|
||||
|
||||
private void save(DialogInterface dialogInterface, int which) {
|
||||
if(mSelectedGameVersion == null) {
|
||||
dialogInterface.dismiss();
|
||||
return;
|
||||
}
|
||||
PerVersionConfig.VersionConfig conf1 = PerVersionConfig.configMap.get(selectedGameVersion);
|
||||
if(conf1==null){
|
||||
conf1=new PerVersionConfig.VersionConfig();
|
||||
|
||||
PerVersionConfig.VersionConfig versionConfig = PerVersionConfig.configMap.get(mSelectedGameVersion);
|
||||
if(versionConfig == null){
|
||||
versionConfig = new PerVersionConfig.VersionConfig();
|
||||
}
|
||||
conf1.jvmArgs=jvmArgsEditText.getText().toString();
|
||||
conf1.gamePath=customDirText.getText().toString();
|
||||
versionConfig.jvmArgs= mJvmArgsEditText.getText().toString();
|
||||
versionConfig.gamePath= mCustomDirEditText.getText().toString();
|
||||
|
||||
if(rendererSpinner.getSelectedItemPosition() == renderNames.size()) conf1.renderer = null;
|
||||
else conf1.renderer = renderNames.get(rendererSpinner.getSelectedItemPosition());
|
||||
if(mRendererSpinner.getSelectedItemPosition() == mRendererNames.size()) versionConfig.renderer = null;
|
||||
else versionConfig.renderer = mRendererNames.get(mRendererSpinner.getSelectedItemPosition());
|
||||
|
||||
String runtime=((MultiRTUtils.Runtime)javaVMSpinner.getSelectedItem()).name;;
|
||||
if(!runtime.equals("<Default>"))conf1.selectedRuntime=runtime;
|
||||
else conf1.selectedRuntime=null;
|
||||
String runtime=((Runtime) mJvmSpinner.getSelectedItem()).name;;
|
||||
if(!runtime.equals("<Default>"))versionConfig.selectedRuntime=runtime;
|
||||
else versionConfig.selectedRuntime = null;
|
||||
|
||||
PerVersionConfig.configMap.put(selectedGameVersion,conf1);
|
||||
PerVersionConfig.configMap.put(mSelectedGameVersion, versionConfig);
|
||||
try{
|
||||
PerVersionConfig.update();
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openConfig(String selectedVersion) {
|
||||
selectedGameVersion = selectedVersion;
|
||||
mSelectedGameVersion = selectedVersion;
|
||||
try{
|
||||
PerVersionConfig.update();
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
PerVersionConfig.VersionConfig conf=PerVersionConfig.configMap.get(selectedGameVersion);
|
||||
PerVersionConfig.VersionConfig versionConfig = PerVersionConfig.configMap.get(mSelectedGameVersion);
|
||||
refreshRuntimes();
|
||||
javaVMSpinner.setAdapter(new RTSpinnerAdapter(ctx,runtimes));
|
||||
{
|
||||
int jvm_index = runtimes.indexOf(new MultiRTUtils.Runtime("<Default>"));
|
||||
int rnd_index = rendererSpinner.getAdapter().getCount()-1;
|
||||
if (conf != null) {
|
||||
customDirText.setText(conf.gamePath);
|
||||
jvmArgsEditText.setText(conf.jvmArgs);
|
||||
if (conf.selectedRuntime != null) {
|
||||
int nindex = runtimes.indexOf(new MultiRTUtils.Runtime(conf.selectedRuntime));
|
||||
if (nindex != -1) jvm_index = nindex;
|
||||
}
|
||||
if(conf.renderer != null) {
|
||||
int nindex = renderNames.indexOf(conf.renderer);
|
||||
if (nindex != -1) rnd_index = nindex;
|
||||
}
|
||||
mJvmSpinner.setAdapter(new RTSpinnerAdapter(mContext, mRuntimes));
|
||||
|
||||
int jvmIndex = mRuntimes.indexOf(new Runtime("<Default>"));
|
||||
int rendererIndex = mRendererSpinner.getAdapter().getCount()-1;
|
||||
if (versionConfig != null) {
|
||||
mCustomDirEditText.setText(versionConfig.gamePath);
|
||||
mJvmArgsEditText.setText(versionConfig.jvmArgs);
|
||||
if (versionConfig.selectedRuntime != null) {
|
||||
int nIndex = mRuntimes.indexOf(new Runtime(versionConfig.selectedRuntime));
|
||||
if (nIndex != -1) jvmIndex = nIndex;
|
||||
}
|
||||
if(versionConfig.renderer != null) {
|
||||
int nIndex = mRendererNames.indexOf(versionConfig.renderer);
|
||||
if (nIndex != -1) rendererIndex = nIndex;
|
||||
}
|
||||
javaVMSpinner.setSelection(jvm_index);
|
||||
rendererSpinner.setSelection(rnd_index);
|
||||
}
|
||||
dialog.show();
|
||||
mJvmSpinner.setSelection(jvmIndex);
|
||||
mRendererSpinner.setSelection(rendererIndex);
|
||||
|
||||
mDialog.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.util.AttributeSet;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import net.kdt.pojavlaunch.BaseLauncherActivity;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
|
||||
|
||||
public class RuntimeManagerPreference extends Preference{
|
||||
public RuntimeManagerPreference(Context ctx) {
|
||||
@@ -17,9 +16,10 @@ public class RuntimeManagerPreference extends Preference{
|
||||
super(ctx, attrs);
|
||||
setPersistent(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
super.onClick();
|
||||
((BaseLauncherActivity)this.getContext()).mRuntimeConfigDialog.dialog.show();
|
||||
((BaseLauncherActivity)this.getContext()).mRuntimeConfigDialog.mDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class GameFolderProvider extends DocumentsProvider {
|
||||
static File baseDir = new File(Tools.DIR_GAME_HOME);
|
||||
static File sBaseDir = new File(Tools.DIR_GAME_HOME);
|
||||
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
|
||||
Root.COLUMN_ROOT_ID,
|
||||
Root.COLUMN_MIME_TYPES,
|
||||
@@ -47,13 +47,13 @@ public class GameFolderProvider extends DocumentsProvider {
|
||||
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
|
||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
||||
final MatrixCursor.RowBuilder row = result.newRow();
|
||||
row.add(Root.COLUMN_ROOT_ID, baseDir.getAbsolutePath());
|
||||
row.add(Root.COLUMN_DOCUMENT_ID, baseDir.getAbsolutePath());
|
||||
row.add(Root.COLUMN_ROOT_ID, sBaseDir.getAbsolutePath());
|
||||
row.add(Root.COLUMN_DOCUMENT_ID, sBaseDir.getAbsolutePath());
|
||||
row.add(Root.COLUMN_SUMMARY, null);
|
||||
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_SEARCH);
|
||||
row.add(Root.COLUMN_TITLE, getContext().getString(R.string.app_name));
|
||||
row.add(Root.COLUMN_MIME_TYPES, "*/*");
|
||||
row.add(Root.COLUMN_AVAILABLE_BYTES, baseDir.getFreeSpace());
|
||||
row.add(Root.COLUMN_AVAILABLE_BYTES, sBaseDir.getFreeSpace());
|
||||
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||
return result;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class GameFolderProvider extends DocumentsProvider {
|
||||
final File file = pending.removeFirst();
|
||||
boolean isInsideGameDir;
|
||||
try {
|
||||
isInsideGameDir = file.getCanonicalPath().startsWith(baseDir.getCanonicalPath());
|
||||
isInsideGameDir = file.getCanonicalPath().startsWith(sBaseDir.getCanonicalPath());
|
||||
} catch (IOException e) {
|
||||
isInsideGameDir = true;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,15 @@ package net.kdt.pojavlaunch.tasks;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
|
||||
import net.kdt.pojavlaunch.multirt.Runtime;
|
||||
import net.kdt.pojavlaunch.prefs.*;
|
||||
import net.kdt.pojavlaunch.utils.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
@@ -280,7 +279,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
|
||||
setMax(assets.objects.size());
|
||||
zeroProgress();
|
||||
try {
|
||||
downloadAssets(assets, verInfo.assets, assets.map_to_resources ? new File(Tools.OBSOLETE_RESOURCES_PATH) : new File(Tools.ASSETS_PATH));
|
||||
downloadAssets(assets, verInfo.assets, assets.mapToResources ? new File(Tools.OBSOLETE_RESOURCES_PATH) : new File(Tools.ASSETS_PATH));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -382,7 +381,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Throwable p1)
|
||||
public void onPostExecute(Throwable p1)
|
||||
{
|
||||
mActivity.mPlayButton.setText("Play");
|
||||
mActivity.mPlayButton.setEnabled(true);
|
||||
@@ -466,7 +465,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
|
||||
JAssetInfo asset = assetsObjects.get(assetKey);
|
||||
assetsSizeBytes+=asset.size;
|
||||
String assetPath = asset.hash.substring(0, 2) + "/" + asset.hash;
|
||||
File outFile = assets.map_to_resources?new File(objectsDir,"/"+assetKey):new File(objectsDir, assetPath);
|
||||
File outFile = assets.mapToResources ?new File(objectsDir,"/"+assetKey):new File(objectsDir, assetPath);
|
||||
boolean skip = outFile.exists();// skip if the file exists
|
||||
if(LauncherPreferences.PREF_CHECK_LIBRARY_SHA) //if sha checking is enabled
|
||||
if(skip) skip = Tools.compareSHA1(outFile, asset.hash); //check hash
|
||||
@@ -476,7 +475,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
|
||||
if(outFile.exists()) publishProgress("0",mActivity.getString(R.string.dl_library_sha_fail,assetKey));
|
||||
executor.execute(()->{
|
||||
try {
|
||||
if (!assets.map_to_resources) {
|
||||
if (!assets.mapToResources) {
|
||||
downloadAsset(asset, objectsDir, downloadedSize);
|
||||
} else {
|
||||
downloadAssetMapped(asset, assetKey, outputDir, downloadedSize);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.kdt.pojavlaunch.utils;
|
||||
|
||||
import static net.kdt.pojavlaunch.Architecture.ARCH_X86;
|
||||
import static net.kdt.pojavlaunch.Architecture.archAsString;
|
||||
import static net.kdt.pojavlaunch.Architecture.is64BitsDevice;
|
||||
import static net.kdt.pojavlaunch.Tools.LOCAL_RENDERER;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GLES_SHRINK_HACK;
|
||||
@@ -15,7 +14,6 @@ import android.system.*;
|
||||
import android.util.*;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kdt.LoggerView;
|
||||
import com.oracle.dalvik.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
@@ -32,21 +30,20 @@ public class JREUtils {
|
||||
private JREUtils() {}
|
||||
|
||||
public static String LD_LIBRARY_PATH;
|
||||
private static String nativeLibDir;
|
||||
public static Map<String, String> jreReleaseList;
|
||||
public static String jvmLibraryPath;
|
||||
private static String sNativeLibDir;
|
||||
|
||||
public static String findInLdLibPath(String libName) {
|
||||
if(Os.getenv("LD_LIBRARY_PATH")==null) {
|
||||
try {
|
||||
if (LD_LIBRARY_PATH != null) {
|
||||
Os.setenv("LD_LIBRARY_PATH", LD_LIBRARY_PATH, true);
|
||||
}else{
|
||||
return libName;
|
||||
}
|
||||
}catch (ErrnoException e) {
|
||||
e.printStackTrace();
|
||||
return libName;
|
||||
}
|
||||
return libName;
|
||||
}
|
||||
for (String libPath : Os.getenv("LD_LIBRARY_PATH").split(":")) {
|
||||
File f = new File(libPath, libName);
|
||||
@@ -56,18 +53,22 @@ public class JREUtils {
|
||||
}
|
||||
return libName;
|
||||
}
|
||||
|
||||
public static ArrayList<File> locateLibs(File path) {
|
||||
ArrayList<File> ret = new ArrayList<>();
|
||||
ArrayList<File> returnValue = new ArrayList<>();
|
||||
File[] list = path.listFiles();
|
||||
if(list != null) {for(File f : list) {
|
||||
if(f.isFile() && f.getName().endsWith(".so")) {
|
||||
ret.add(f);
|
||||
}else if(f.isDirectory()) {
|
||||
ret.addAll(locateLibs(f));
|
||||
if(list != null) {
|
||||
for(File f : list) {
|
||||
if(f.isFile() && f.getName().endsWith(".so")) {
|
||||
returnValue.add(f);
|
||||
}else if(f.isDirectory()) {
|
||||
returnValue.addAll(locateLibs(f));
|
||||
}
|
||||
}
|
||||
}}
|
||||
return ret;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public static void initJavaRuntime() {
|
||||
dlopen(findInLdLibPath("libjli.so"));
|
||||
if(!dlopen("libjvm.so")){
|
||||
@@ -86,13 +87,13 @@ public class JREUtils {
|
||||
for(File f : locateLibs(new File(Tools.DIR_HOME_JRE + "/" + Tools.DIRNAME_HOME_JRE))) {
|
||||
dlopen(f.getAbsolutePath());
|
||||
}
|
||||
dlopen(nativeLibDir + "/libopenal.so");
|
||||
|
||||
dlopen(sNativeLibDir + "/libopenal.so");
|
||||
}
|
||||
|
||||
public static Map<String, String> readJREReleaseProperties() throws IOException {
|
||||
return readJREReleaseProperties(Tools.DIR_HOME_JRE);
|
||||
}
|
||||
|
||||
public static Map<String, String> readJREReleaseProperties(String name) throws IOException {
|
||||
Map<String, String> jreReleaseMap = new ArrayMap<>();
|
||||
if (!name.contains("/")) {
|
||||
@@ -109,11 +110,11 @@ public class JREUtils {
|
||||
jreReleaseReader.close();
|
||||
return jreReleaseMap;
|
||||
}
|
||||
public static String jvmLibraryPath;
|
||||
public static void redirectAndPrintJRELog(final Context ctx) {
|
||||
|
||||
public static void redirectAndPrintJRELog() {
|
||||
Log.v("jrelog","Log starts here");
|
||||
JREUtils.logToLogger(Logger.getInstance());
|
||||
Thread t = new Thread(new Runnable(){
|
||||
new Thread(new Runnable(){
|
||||
int failTime = 0;
|
||||
ProcessBuilder logcatPb;
|
||||
@Override
|
||||
@@ -128,16 +129,6 @@ public class JREUtils {
|
||||
Log.i("jrelog-logcat","Starting logcat");
|
||||
java.lang.Process p = logcatPb.start();
|
||||
|
||||
// idk which better, both have a bug that printf(\n) in a single line
|
||||
/*
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
act.appendlnToLog(line);
|
||||
}
|
||||
reader.close();
|
||||
*/
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = p.getInputStream().read(buf)) != -1) {
|
||||
@@ -161,8 +152,7 @@ public class JREUtils {
|
||||
Logger.getInstance().appendToLog("Exception on logging thread:\n" + Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}).start();
|
||||
Log.i("jrelog-logcat","Logcat thread started");
|
||||
}
|
||||
|
||||
@@ -172,7 +162,7 @@ public class JREUtils {
|
||||
JRE_ARCHITECTURE = "i386/i486/i586";
|
||||
}
|
||||
|
||||
nativeLibDir = ctx.getApplicationInfo().nativeLibraryDir;
|
||||
sNativeLibDir = ctx.getApplicationInfo().nativeLibraryDir;
|
||||
|
||||
for (String arch : JRE_ARCHITECTURE.split("/")) {
|
||||
File f = new File(Tools.DIR_HOME_JRE, "lib/" + arch);
|
||||
@@ -191,7 +181,7 @@ public class JREUtils {
|
||||
"/system/" + libName + ":" +
|
||||
"/vendor/" + libName + ":" +
|
||||
"/vendor/" + libName + "/hw:" +
|
||||
nativeLibDir
|
||||
sNativeLibDir
|
||||
);
|
||||
LD_LIBRARY_PATH = ldLibraryPath.toString();
|
||||
}
|
||||
@@ -461,7 +451,7 @@ public class JREUtils {
|
||||
Log.e("RENDER_LIBRARY","Failed to load renderer " + renderLibrary + ". Falling back to GL4ES 1.1.4");
|
||||
LOCAL_RENDERER = "opengles2";
|
||||
renderLibrary = "libgl4es_114.so";
|
||||
dlopen(nativeLibDir + "/libgl4es_114.so");
|
||||
dlopen(sNativeLibDir + "/libgl4es_114.so");
|
||||
}
|
||||
return renderLibrary;
|
||||
}
|
||||
|
||||
@@ -20,22 +20,21 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class MCOptionUtils
|
||||
{
|
||||
private static final HashMap<String,String> parameterMap = new HashMap<>();
|
||||
private static final ArrayList<WeakReference<MCOptionListener>> optionListeners = new ArrayList<>();
|
||||
private static FileObserver fileObserver;
|
||||
public class MCOptionUtils {
|
||||
private static final HashMap<String,String> sParameterMap = new HashMap<>();
|
||||
private static final ArrayList<WeakReference<MCOptionListener>> sOptionListeners = new ArrayList<>();
|
||||
private static FileObserver sFileObserver;
|
||||
public interface MCOptionListener {
|
||||
/** Called when an option is changed. Don't know which one though */
|
||||
void onOptionChanged();
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
if(fileObserver == null){
|
||||
if(sFileObserver == null){
|
||||
setupFileObserver();
|
||||
}
|
||||
|
||||
parameterMap.clear();
|
||||
sParameterMap.clear();
|
||||
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(Tools.DIR_GAME_NEW + "/options.txt"));
|
||||
@@ -46,7 +45,7 @@ public class MCOptionUtils
|
||||
Log.w(Tools.APP_NAME, "No colon on line \""+line+"\", skipping");
|
||||
continue;
|
||||
}
|
||||
parameterMap.put(line.substring(0,firstColonIndex), line.substring(firstColonIndex+1));
|
||||
sParameterMap.put(line.substring(0,firstColonIndex), line.substring(firstColonIndex+1));
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
@@ -55,16 +54,16 @@ public class MCOptionUtils
|
||||
}
|
||||
|
||||
public static void set(String key, String value) {
|
||||
parameterMap.put(key,value);
|
||||
sParameterMap.put(key,value);
|
||||
}
|
||||
|
||||
/** Set an array of String, instead of a simple value. Not supported on all options */
|
||||
public static void set(String key, List<String> values){
|
||||
parameterMap.put(key, values.toString());
|
||||
sParameterMap.put(key, values.toString());
|
||||
}
|
||||
|
||||
public static String get(String key){
|
||||
return parameterMap.get(key);
|
||||
return sParameterMap.get(key);
|
||||
}
|
||||
|
||||
/** @return A list of values from an array stored as a string */
|
||||
@@ -83,10 +82,10 @@ public class MCOptionUtils
|
||||
|
||||
public static void save() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(String key : parameterMap.keySet())
|
||||
for(String key : sParameterMap.keySet())
|
||||
result.append(key)
|
||||
.append(':')
|
||||
.append(parameterMap.get(key))
|
||||
.append(sParameterMap.get(key))
|
||||
.append('\n');
|
||||
|
||||
try {
|
||||
@@ -114,7 +113,7 @@ public class MCOptionUtils
|
||||
* Listeners get notified of the change */
|
||||
private static void setupFileObserver(){
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
|
||||
fileObserver = new FileObserver(new File(Tools.DIR_GAME_NEW + "/options.txt"), FileObserver.MODIFY) {
|
||||
sFileObserver = new FileObserver(new File(Tools.DIR_GAME_NEW + "/options.txt"), FileObserver.MODIFY) {
|
||||
@Override
|
||||
public void onEvent(int i, @Nullable String s) {
|
||||
MCOptionUtils.load();
|
||||
@@ -122,7 +121,7 @@ public class MCOptionUtils
|
||||
}
|
||||
};
|
||||
}else{
|
||||
fileObserver = new FileObserver(Tools.DIR_GAME_NEW + "/options.txt", FileObserver.MODIFY) {
|
||||
sFileObserver = new FileObserver(Tools.DIR_GAME_NEW + "/options.txt", FileObserver.MODIFY) {
|
||||
@Override
|
||||
public void onEvent(int i, @Nullable String s) {
|
||||
MCOptionUtils.load();
|
||||
@@ -131,12 +130,12 @@ public class MCOptionUtils
|
||||
};
|
||||
}
|
||||
|
||||
fileObserver.startWatching();
|
||||
sFileObserver.startWatching();
|
||||
}
|
||||
|
||||
/** Notify the option listeners */
|
||||
public static void notifyListeners(){
|
||||
for(WeakReference<MCOptionListener> weakReference : optionListeners){
|
||||
for(WeakReference<MCOptionListener> weakReference : sOptionListeners){
|
||||
MCOptionListener optionListener = weakReference.get();
|
||||
if(optionListener == null) continue;
|
||||
|
||||
@@ -146,16 +145,16 @@ public class MCOptionUtils
|
||||
|
||||
/** Add an option listener, notice how we don't have a reference to it */
|
||||
public static void addMCOptionListener(MCOptionListener listener){
|
||||
optionListeners.add(new WeakReference<>(listener));
|
||||
sOptionListeners.add(new WeakReference<>(listener));
|
||||
}
|
||||
|
||||
/** Remove a listener from existence, or at least, its reference here */
|
||||
public static void removeMCOptionListener(MCOptionListener listener){
|
||||
for(WeakReference<MCOptionListener> weakReference : optionListeners){
|
||||
for(WeakReference<MCOptionListener> weakReference : sOptionListeners){
|
||||
MCOptionListener optionListener = weakReference.get();
|
||||
if(optionListener == null) continue;
|
||||
if(optionListener == listener){
|
||||
optionListeners.remove(weakReference);
|
||||
sOptionListeners.remove(weakReference);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,15 +95,17 @@ public class V117CompatUtil {
|
||||
Log.i("V117CompatDebug",rawList);
|
||||
return new ArrayList<>(Arrays.asList(rawList.split(",")));
|
||||
}
|
||||
|
||||
private static String regenPackList(List<String> packs) {
|
||||
if(packs.size()==0) return "[]";
|
||||
String ret = "["+packs.get(0);
|
||||
StringBuilder ret = new StringBuilder("[" + packs.get(0));
|
||||
for(int i = 1; i < packs.size(); i++) {
|
||||
ret += ","+packs.get(i);
|
||||
ret.append(",").append(packs.get(i));
|
||||
}
|
||||
ret += "]";
|
||||
return ret;
|
||||
ret.append("]");
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public static void runCheck(String version, Activity ctx) throws Exception{
|
||||
|
||||
|
||||
@@ -132,25 +134,25 @@ public class V117CompatUtil {
|
||||
Object lock = new Object();
|
||||
AtomicInteger proceed = new AtomicInteger(0);
|
||||
ctx.runOnUiThread(() -> {
|
||||
AlertDialog.Builder bldr = new AlertDialog.Builder(ctx);
|
||||
bldr.setTitle(R.string.global_warinng);
|
||||
bldr.setMessage(R.string.compat_117_message);
|
||||
bldr.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||
builder.setTitle(R.string.global_warinng);
|
||||
builder.setMessage(R.string.compat_117_message);
|
||||
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
proceed.set(1);
|
||||
synchronized (lock) { lock.notifyAll(); }
|
||||
dialog.dismiss();
|
||||
});
|
||||
bldr.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||
builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||
synchronized (lock) { lock.notifyAll(); }
|
||||
dialog.dismiss();
|
||||
});
|
||||
bldr.setNeutralButton(R.string.compat_11x_playanyway, (dialog, which) -> {
|
||||
builder.setNeutralButton(R.string.compat_11x_playanyway, (dialog, which) -> {
|
||||
proceed.set(2);
|
||||
synchronized (lock) { lock.notifyAll(); }
|
||||
dialog.dismiss();
|
||||
});
|
||||
bldr.setCancelable(false);
|
||||
bldr.show();
|
||||
builder.setCancelable(false);
|
||||
builder.show();
|
||||
});
|
||||
|
||||
synchronized (lock) {
|
||||
@@ -182,6 +184,7 @@ public class V117CompatUtil {
|
||||
throw new MinecraftDownloaderTask.SilentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyResourcePack(String gameDir, AssetManager am) throws IOException {
|
||||
File resourcepacksDir = new File(gameDir,"resourcepacks");
|
||||
if(!resourcepacksDir.exists()) resourcepacksDir.mkdirs();
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package org.lwjgl.glfw;
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.widget.*;
|
||||
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import android.content.*;
|
||||
|
||||
@@ -20,6 +16,9 @@ public class CallbackBridge {
|
||||
public static volatile int physicalWidth, physicalHeight;
|
||||
public static float mouseX, mouseY;
|
||||
public static StringBuilder DEBUG_STRING = new StringBuilder();
|
||||
private static boolean threadAttached;
|
||||
public volatile static boolean holdingAlt, holdingCapslock, holdingCtrl,
|
||||
holdingNumlock, holdingShift;
|
||||
|
||||
|
||||
public static void putMouseEventWithCoords(int button, float x, float y) {
|
||||
@@ -34,7 +33,7 @@ public class CallbackBridge {
|
||||
sendMouseKeycode(button, CallbackBridge.getCurrentMods(), isDown);
|
||||
}
|
||||
|
||||
private static boolean threadAttached;
|
||||
|
||||
public static void sendCursorPos(float x, float y) {
|
||||
if (!threadAttached) {
|
||||
threadAttached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
|
||||
@@ -158,43 +157,42 @@ public class CallbackBridge {
|
||||
private static native void nativeSendData(boolean isAndroid, int type, String data);
|
||||
*/
|
||||
|
||||
public volatile static boolean holdingAlt, holdingCapslock, holdingCtrl,
|
||||
holdingNumlock, holdingShift;
|
||||
|
||||
public static int getCurrentMods() {
|
||||
int currMods = 0;
|
||||
if (holdingAlt) {
|
||||
currMods |= LWJGLGLFWKeycode.GLFW_MOD_ALT;
|
||||
currMods |= LwjglGlfwKeycode.GLFW_MOD_ALT;
|
||||
} if (holdingCapslock) {
|
||||
currMods |= LWJGLGLFWKeycode.GLFW_MOD_CAPS_LOCK;
|
||||
currMods |= LwjglGlfwKeycode.GLFW_MOD_CAPS_LOCK;
|
||||
} if (holdingCtrl) {
|
||||
currMods |= LWJGLGLFWKeycode.GLFW_MOD_CONTROL;
|
||||
currMods |= LwjglGlfwKeycode.GLFW_MOD_CONTROL;
|
||||
} if (holdingNumlock) {
|
||||
currMods |= LWJGLGLFWKeycode.GLFW_MOD_NUM_LOCK;
|
||||
currMods |= LwjglGlfwKeycode.GLFW_MOD_NUM_LOCK;
|
||||
} if (holdingShift) {
|
||||
currMods |= LWJGLGLFWKeycode.GLFW_MOD_SHIFT;
|
||||
currMods |= LwjglGlfwKeycode.GLFW_MOD_SHIFT;
|
||||
}
|
||||
return currMods;
|
||||
}
|
||||
|
||||
public static void setModifiers(int keyCode, boolean isDown){
|
||||
switch (keyCode){
|
||||
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT:
|
||||
case LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT:
|
||||
CallbackBridge.holdingShift = isDown;
|
||||
return;
|
||||
|
||||
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL:
|
||||
case LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL:
|
||||
CallbackBridge.holdingCtrl = isDown;
|
||||
return;
|
||||
|
||||
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT:
|
||||
case LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT:
|
||||
CallbackBridge.holdingAlt = isDown;
|
||||
return;
|
||||
|
||||
case LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK:
|
||||
case LwjglGlfwKeycode.GLFW_KEY_CAPS_LOCK:
|
||||
CallbackBridge.holdingCapslock = isDown;
|
||||
return;
|
||||
|
||||
case LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK:
|
||||
case LwjglGlfwKeycode.GLFW_KEY_NUM_LOCK:
|
||||
CallbackBridge.holdingNumlock = isDown;
|
||||
return;
|
||||
}
|
||||
@@ -211,7 +209,8 @@ public class CallbackBridge {
|
||||
private static native void nativeSendMouseButton(int button, int action, int mods);
|
||||
private static native void nativeSendScroll(double xoffset, double yoffset);
|
||||
private static native void nativeSendScreenSize(int width, int height);
|
||||
|
||||
public static native void nativeSetWindowAttrib(int attrib, int value);
|
||||
|
||||
public static native boolean nativeIsGrabbing();
|
||||
static {
|
||||
System.loadLibrary("pojavexec");
|
||||
|
||||
@@ -363,3 +363,21 @@ 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_nativeSetWindowAttrib(JNIEnv* env, jclass clazz, jint attrib, jint value) {
|
||||
if (!showingWindow) {
|
||||
return; // nothing to do yet
|
||||
}
|
||||
|
||||
jclass glfwClazz = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID, "org/lwjgl/glfw/GLFW");
|
||||
assert(glfwClazz != NULL);
|
||||
jmethodID glfwMethod = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, glfwMethod, "glfwSetWindowAttrib", "(JII)V");
|
||||
assert(glfwMethod != NULL);
|
||||
|
||||
(*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod(
|
||||
runtimeJNIEnvPtr_ANDROID,
|
||||
glfwClazz, glfwMethod,
|
||||
(jlong) showingWindow, attrib, value
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="300"
|
||||
android:fromXDelta="100%"
|
||||
android:toXDelta="0%"/>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromXDelta="0%" android:toXDelta="100%"
|
||||
android:fromYDelta="0%" android:toYDelta="0%"
|
||||
android:duration="300"/>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 478 B |
|
Before Width: | Height: | Size: 486 B |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
0
app_pojavlauncher/src/main/res/drawable-mdpi/jre_args.png → app_pojavlauncher/src/main/res/drawable-mdpi/ic_setting_jre_args.png
Executable file → Normal file
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |