mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-13 14:51:51 -04:00
Feat[input]: Minecraft hotbar as a View
This commit is contained in:
parent
781341eafd
commit
6bac7ee10b
@ -75,7 +75,7 @@ public class MinecraftGLSurface extends View implements GrabListener {
|
|||||||
/* View holding the surface, either a SurfaceView or a TextureView */
|
/* View holding the surface, either a SurfaceView or a TextureView */
|
||||||
View mSurface;
|
View mSurface;
|
||||||
|
|
||||||
private final TouchEventProcessor mIngameProcessor = new InGameEventProcessor(mScaleFactor, mSensitivityFactor);
|
private final TouchEventProcessor mIngameProcessor = new InGameEventProcessor(mSensitivityFactor);
|
||||||
private final TouchEventProcessor mInGUIProcessor = new InGUIEventProcessor(mScaleFactor);
|
private final TouchEventProcessor mInGUIProcessor = new InGUIEventProcessor(mScaleFactor);
|
||||||
private boolean mLastGrabState = false;
|
private boolean mLastGrabState = false;
|
||||||
|
|
||||||
|
@ -15,12 +15,11 @@ public class DropGesture implements Runnable{
|
|||||||
this.mHandler = mHandler;
|
this.mHandler = mHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit(boolean hasGuiBarHit) {
|
public void submit() {
|
||||||
if(hasGuiBarHit && !mActive) {
|
if(!mActive) {
|
||||||
mActive = true;
|
mActive = true;
|
||||||
mHandler.postDelayed(this, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
|
mHandler.postDelayed(this, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
|
||||||
}
|
}
|
||||||
if(!hasGuiBarHit && mActive) cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
package net.kdt.pojavlaunch.customcontrols.mouse;
|
|
||||||
|
|
||||||
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
|
||||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
|
||||||
import net.kdt.pojavlaunch.utils.MCOptionUtils;
|
|
||||||
|
|
||||||
import org.lwjgl.glfw.CallbackBridge;
|
|
||||||
|
|
||||||
public class HotbarTracker implements MCOptionUtils.MCOptionListener {
|
|
||||||
|
|
||||||
private static final int[] HOTBAR_KEYS = {
|
|
||||||
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
|
|
||||||
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
|
|
||||||
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
|
|
||||||
private int mLastHudKey, mHudPointerId;
|
|
||||||
private final DropGesture mDropGesture;
|
|
||||||
private int mBarWidth, mBarHeight;
|
|
||||||
private final float mScaleFactor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mGestureHandler the gesture handler for the integrated drop gesture
|
|
||||||
* @param mScaleFactor the screen scale factor
|
|
||||||
*/
|
|
||||||
public HotbarTracker(Handler mGestureHandler, float mScaleFactor) {
|
|
||||||
computeBarDimensions();
|
|
||||||
MCOptionUtils.addMCOptionListener(this);
|
|
||||||
this.mScaleFactor = mScaleFactor;
|
|
||||||
mDropGesture = new DropGesture(mGestureHandler);
|
|
||||||
mHudPointerId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean begin(MotionEvent motionEvent, boolean hasDoubleTapped) {
|
|
||||||
if(mHudPointerId != -1) return false;
|
|
||||||
int pointer = motionEvent.getActionIndex();
|
|
||||||
if(motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) pointer = 0;
|
|
||||||
int x = (int)motionEvent.getX(pointer);
|
|
||||||
if(isWithinHotbar(x, (int)motionEvent.getY(pointer))) {
|
|
||||||
mHudPointerId = motionEvent.getPointerId(pointer);
|
|
||||||
hotbarClick(x, hasDoubleTapped);
|
|
||||||
mDropGesture.submit(true);
|
|
||||||
return true;
|
|
||||||
}else {
|
|
||||||
mHudPointerId = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean track(MotionEvent motionEvent, int trackedIndex, boolean hasDoubleTapped) {
|
|
||||||
if(mHudPointerId == -1) return false;
|
|
||||||
int index = motionEvent.findPointerIndex(mHudPointerId);
|
|
||||||
if(index == -1) {
|
|
||||||
cancel();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int x = (int)motionEvent.getX(index);
|
|
||||||
if(isWithinHotbar(x, (int)motionEvent.getY(index))) {
|
|
||||||
hotbarClick(x, hasDoubleTapped);
|
|
||||||
mDropGesture.submit(true);
|
|
||||||
}else {
|
|
||||||
mDropGesture.submit(false);
|
|
||||||
}
|
|
||||||
return trackedIndex == index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
mDropGesture.cancel();
|
|
||||||
mHudPointerId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWithinHotbar(int x, int y) {
|
|
||||||
int barY = CallbackBridge.physicalHeight - mBarHeight;
|
|
||||||
if(y < barY) return false;
|
|
||||||
|
|
||||||
int barX = (CallbackBridge.physicalWidth / 2) - (mBarWidth / 2);
|
|
||||||
return x >= barX && x < barX + mBarWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hotbarClick(int x, boolean hasDoubleTapped) {
|
|
||||||
if(hasDoubleTapped && !LauncherPreferences.PREF_DISABLE_SWAP_HAND) {
|
|
||||||
CallbackBridge.sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
|
||||||
}
|
|
||||||
|
|
||||||
int barX = (CallbackBridge.physicalWidth / 2) - (mBarWidth / 2);
|
|
||||||
if(x < barX || x >= barX + mBarWidth) return;
|
|
||||||
|
|
||||||
int key = HOTBAR_KEYS[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + mBarWidth, 0, 9)];
|
|
||||||
if(key != mLastHudKey) {
|
|
||||||
CallbackBridge.sendKeyPress(key);
|
|
||||||
// The GUI bar is handled before the gesture will be submitted, so this
|
|
||||||
// will be resubmitted again soon (with the timer restarted)
|
|
||||||
mDropGesture.cancel();
|
|
||||||
mLastHudKey = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int mcScale(int input, int guiScale) {
|
|
||||||
return (int)((guiScale * input)/ mScaleFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void computeBarDimensions() {
|
|
||||||
int guiScale = getMcScale();
|
|
||||||
mBarHeight = mcScale(20, guiScale);
|
|
||||||
mBarWidth = mcScale(180, guiScale);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onOptionChanged() {
|
|
||||||
computeBarDimensions();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,150 @@
|
|||||||
|
package net.kdt.pojavlaunch.customcontrols.mouse;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||||
|
import net.kdt.pojavlaunch.TapDetector;
|
||||||
|
import net.kdt.pojavlaunch.Tools;
|
||||||
|
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||||
|
import net.kdt.pojavlaunch.utils.MCOptionUtils;
|
||||||
|
import net.kdt.pojavlaunch.utils.MathUtils;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.CallbackBridge;
|
||||||
|
|
||||||
|
public class HotbarView extends View implements MCOptionUtils.MCOptionListener, View.OnLayoutChangeListener, Runnable {
|
||||||
|
private final TapDetector mDoubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
|
||||||
|
private static final int[] HOTBAR_KEYS = {
|
||||||
|
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
|
||||||
|
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
|
||||||
|
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
|
||||||
|
private final DropGesture mDropGesture = new DropGesture(new Handler(Looper.getMainLooper()));
|
||||||
|
private final float mScaleFactor = LauncherPreferences.PREF_SCALE_FACTOR/100f;
|
||||||
|
private int mWidth;
|
||||||
|
private int mLastIndex;
|
||||||
|
private int mGuiScale;
|
||||||
|
|
||||||
|
public HotbarView(Context context) {
|
||||||
|
super(context);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotbarView(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotbarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // You suggested me this constructor, Android
|
||||||
|
public HotbarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
MCOptionUtils.addMCOptionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
ViewParent parent = getParent();
|
||||||
|
if(parent == null) return;
|
||||||
|
if(parent instanceof View) {
|
||||||
|
View parentView = (View) parent;
|
||||||
|
parentView.addOnLayoutChangeListener(this);
|
||||||
|
}
|
||||||
|
mGuiScale = MCOptionUtils.getMcScale();
|
||||||
|
repositionView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repositionView() {
|
||||||
|
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||||
|
if(!(layoutParams instanceof ViewGroup.MarginLayoutParams))
|
||||||
|
throw new RuntimeException("Incorrect LayoutParams type, expected ViewGroup.MarginLayoutParams");
|
||||||
|
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;
|
||||||
|
int height;
|
||||||
|
marginLayoutParams.width = mWidth = mcScale(180);
|
||||||
|
marginLayoutParams.height = height = mcScale(20);
|
||||||
|
marginLayoutParams.leftMargin = (CallbackBridge.physicalWidth / 2) - (mWidth / 2);
|
||||||
|
marginLayoutParams.topMargin = CallbackBridge.physicalHeight - height;
|
||||||
|
setLayoutParams(marginLayoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ClickableViewAccessibility") // performClick does not report coordinates.
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
if(!CallbackBridge.isGrabbing()) return false;
|
||||||
|
// Check if we are double-tapping to swap hands
|
||||||
|
boolean hasDoubleTapped = mDoubleTapDetector.onTouchEvent(event);
|
||||||
|
if(hasDoubleTapped && !LauncherPreferences.PREF_DISABLE_SWAP_HAND) CallbackBridge.sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
|
||||||
|
|
||||||
|
// Check if we need to cancel the drop event
|
||||||
|
int actionMasked = event.getActionMasked();
|
||||||
|
if(isLastEventInGesture(actionMasked)) cancelDropGesture();
|
||||||
|
else submitDropGesture();
|
||||||
|
// Determine the hotbar slot
|
||||||
|
float x = event.getX();
|
||||||
|
if(x < 0 || x > mWidth) return true;
|
||||||
|
int hotbarIndex = (int)MathUtils.map(x, 0, mWidth, 0, HOTBAR_KEYS.length);
|
||||||
|
// Check if the slot changed and we need to make a key press
|
||||||
|
if(hotbarIndex == mLastIndex) return true;
|
||||||
|
mLastIndex = hotbarIndex;
|
||||||
|
int hotbarKey = HOTBAR_KEYS[hotbarIndex];
|
||||||
|
CallbackBridge.sendKeyPress(hotbarKey);
|
||||||
|
// Cancel the event since we changed hotbar slots.
|
||||||
|
cancelDropGesture();
|
||||||
|
// Only resubmit the gesture only if it isn't the last event we will receive.
|
||||||
|
if(!isLastEventInGesture(actionMasked)) submitDropGesture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submitDropGesture() {
|
||||||
|
if(LauncherPreferences.PREF_DISABLE_GESTURES) return;
|
||||||
|
mDropGesture.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelDropGesture() {
|
||||||
|
if(LauncherPreferences.PREF_DISABLE_GESTURES) return;
|
||||||
|
mDropGesture.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLastEventInGesture(int actionMasked) {
|
||||||
|
return actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int mcScale(int input) {
|
||||||
|
return (int)((mGuiScale * input)/ mScaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOptionChanged() {
|
||||||
|
Tools.runOnUiThread(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if(getParent() == null) return;
|
||||||
|
int scale = MCOptionUtils.getMcScale();
|
||||||
|
if(scale == mGuiScale) return;
|
||||||
|
mGuiScale = scale;
|
||||||
|
repositionView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||||
|
repositionView();
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import net.kdt.pojavlaunch.TapDetector;
|
|
||||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||||
|
|
||||||
import org.lwjgl.glfw.CallbackBridge;
|
import org.lwjgl.glfw.CallbackBridge;
|
||||||
@ -13,34 +12,24 @@ public class InGameEventProcessor implements TouchEventProcessor {
|
|||||||
private final Handler mGestureHandler = new Handler(Looper.getMainLooper());
|
private final Handler mGestureHandler = new Handler(Looper.getMainLooper());
|
||||||
private final double mSensitivity;
|
private final double mSensitivity;
|
||||||
private final PointerTracker mTracker = new PointerTracker();
|
private final PointerTracker mTracker = new PointerTracker();
|
||||||
private final HotbarTracker mGuiBarTracker;
|
|
||||||
private final LeftClickGesture mLeftClickGesture = new LeftClickGesture(mGestureHandler);
|
private final LeftClickGesture mLeftClickGesture = new LeftClickGesture(mGestureHandler);
|
||||||
private final RightClickGesture mRightClickGesture = new RightClickGesture(mGestureHandler);
|
private final RightClickGesture mRightClickGesture = new RightClickGesture(mGestureHandler);
|
||||||
private final TapDetector mDoubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
|
|
||||||
|
|
||||||
public InGameEventProcessor(float scaleFactor, double sensitivity) {
|
public InGameEventProcessor(double sensitivity) {
|
||||||
mGuiBarTracker = new HotbarTracker(mGestureHandler, scaleFactor);
|
|
||||||
mSensitivity = sensitivity;
|
mSensitivity = sensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean processTouchEvent(MotionEvent motionEvent) {
|
public boolean processTouchEvent(MotionEvent motionEvent) {
|
||||||
boolean hasDoubleTapped = mDoubleTapDetector.onTouchEvent(motionEvent);
|
|
||||||
switch (motionEvent.getActionMasked()) {
|
switch (motionEvent.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
if(mGuiBarTracker.begin(motionEvent, hasDoubleTapped)) break;
|
|
||||||
mTracker.startTracking(motionEvent);
|
mTracker.startTracking(motionEvent);
|
||||||
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
|
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
|
||||||
checkGestures();
|
checkGestures();
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_POINTER_DOWN:
|
|
||||||
mGuiBarTracker.begin(motionEvent, hasDoubleTapped);
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
int trackedIndex = mTracker.trackEvent(motionEvent);
|
mTracker.trackEvent(motionEvent);
|
||||||
// Don't send mouse positions if there's a finger in the gui bar *and* the camera tracker
|
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
|
||||||
// tracks the same finger as the gui bar.
|
|
||||||
if(mGuiBarTracker.track(motionEvent, trackedIndex, hasDoubleTapped)) break;
|
|
||||||
checkGestures();
|
checkGestures();
|
||||||
float[] motionVector = mTracker.getMotionVector();
|
float[] motionVector = mTracker.getMotionVector();
|
||||||
CallbackBridge.mouseX += motionVector[0] * mSensitivity;
|
CallbackBridge.mouseX += motionVector[0] * mSensitivity;
|
||||||
@ -49,7 +38,6 @@ public class InGameEventProcessor implements TouchEventProcessor {
|
|||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
mGuiBarTracker.cancel();
|
|
||||||
mTracker.cancelTracking();
|
mTracker.cancelTracking();
|
||||||
cancelGestures(false);
|
cancelGestures(false);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public class PointerTracker {
|
|||||||
public int trackEvent(MotionEvent motionEvent) {
|
public int trackEvent(MotionEvent motionEvent) {
|
||||||
int trackedPointerIndex = motionEvent.findPointerIndex(mTrackedPointerId);
|
int trackedPointerIndex = motionEvent.findPointerIndex(mTrackedPointerId);
|
||||||
int pointerCount = motionEvent.getPointerCount();
|
int pointerCount = motionEvent.getPointerCount();
|
||||||
if(trackedPointerIndex == -1 || mPointerCount != pointerCount || mColdStart) {
|
if(trackedPointerIndex == -1 || mPointerCount != pointerCount || mColdStart) {
|
||||||
startTracking(motionEvent);
|
startTracking(motionEvent);
|
||||||
trackedPointerIndex = 0;
|
trackedPointerIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,9 @@
|
|||||||
android:layout_height="12dp"
|
android:layout_height="12dp"
|
||||||
android:elevation="10dp"
|
android:elevation="10dp"
|
||||||
android:layout_gravity="center_horizontal"/>
|
android:layout_gravity="center_horizontal"/>
|
||||||
|
<net.kdt.pojavlaunch.customcontrols.mouse.HotbarView
|
||||||
|
android:layout_width="0px"
|
||||||
|
android:layout_height="0px"/>
|
||||||
|
|
||||||
</net.kdt.pojavlaunch.customcontrols.ControlLayout>
|
</net.kdt.pojavlaunch.customcontrols.ControlLayout>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user