From 7345a4bbe6af11502ad58f9b85257b2c2f6451fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=AA=E8=98=AD=E6=A5=93?= Date: Thu, 20 Jun 2024 18:53:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Xbox=20=E6=89=8B=E6=9F=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/cpp/GakumasLocalify/BaseDefine.h | 13 ++ .../cpp/GakumasLocalify/camera/baseCamera.cpp | 8 +- .../cpp/GakumasLocalify/camera/baseCamera.hpp | 2 +- .../cpp/GakumasLocalify/camera/camera.cpp | 185 ++++++++++++++++-- .../cpp/GakumasLocalify/camera/camera.hpp | 2 + .../main/cpp/deps/Joystick/JoystickEvent.h | 67 +++++++ app/src/main/cpp/libMarryKotone.cpp | 17 ++ .../gakumas/localify/GakumasHookMain.kt | 57 ++++++ 8 files changed, 326 insertions(+), 25 deletions(-) create mode 100644 app/src/main/cpp/deps/Joystick/JoystickEvent.h diff --git a/app/src/main/cpp/GakumasLocalify/BaseDefine.h b/app/src/main/cpp/GakumasLocalify/BaseDefine.h index 5b5cc2d..18a5153 100644 --- a/app/src/main/cpp/GakumasLocalify/BaseDefine.h +++ b/app/src/main/cpp/GakumasLocalify/BaseDefine.h @@ -24,3 +24,16 @@ #define WM_KEYDOWN 0 #define WM_KEYUP 1 + +#define BTN_A 96 +#define BTN_B 97 +#define BTN_X 99 +#define BTN_Y 100 +#define BTN_LB 102 +#define BTN_RB 103 +#define BTN_THUMBL 106 +#define BTN_THUMBR 107 +#define BTN_SELECT 109 +#define BTN_START 108 +#define BTN_SHARE 130 +#define BTN_XBOX 110 \ No newline at end of file diff --git a/app/src/main/cpp/GakumasLocalify/camera/baseCamera.cpp b/app/src/main/cpp/GakumasLocalify/camera/baseCamera.cpp index beb4a8e..8733231 100644 --- a/app/src/main/cpp/GakumasLocalify/camera/baseCamera.cpp +++ b/app/src/main/cpp/GakumasLocalify/camera/baseCamera.cpp @@ -62,14 +62,14 @@ namespace BaseCamera { return lookAt; } - void Camera::set_lon_move(float vertanglePlus, LonMoveHState moveState) { // 前后移动 + void Camera::set_lon_move(float vertanglePlus, LonMoveHState moveState, float multiplier) { // 前后移动 auto radian = (verticalAngle + vertanglePlus) * M_PI / 180; auto radianH = (double)horizontalAngle * M_PI / 180; - auto f_step = cos(radian) * moveStep * cos(radianH) / smoothLevel; // ↑↓ - auto l_step = sin(radian) * moveStep * cos(radianH) / smoothLevel; // ←→ + auto f_step = cos(radian) * moveStep * cos(radianH) / smoothLevel * multiplier; // ↑↓ + auto l_step = sin(radian) * moveStep * cos(radianH) / smoothLevel * multiplier; // ←→ // auto h_step = tan(radianH) * sqrt(pow(f_step, 2) + pow(l_step, 2)); - auto h_step = sin(radianH) * moveStep / smoothLevel; + auto h_step = sin(radianH) * moveStep / smoothLevel * multiplier; switch (moveState) { diff --git a/app/src/main/cpp/GakumasLocalify/camera/baseCamera.hpp b/app/src/main/cpp/GakumasLocalify/camera/baseCamera.hpp index 20051b2..2cfdebb 100644 --- a/app/src/main/cpp/GakumasLocalify/camera/baseCamera.hpp +++ b/app/src/main/cpp/GakumasLocalify/camera/baseCamera.hpp @@ -30,7 +30,7 @@ namespace BaseCamera { void setPos(float x, float y, float z); void setLookAt(float x, float y, float z); - void set_lon_move(float vertanglePlus, LonMoveHState moveState = LonMoveHState::LonMoveLeftAndRight); + void set_lon_move(float vertanglePlus, LonMoveHState moveState = LonMoveHState::LonMoveLeftAndRight, float multiplier = 1.0f); void updateVertLook(); void setHoriLook(float vertangle); diff --git a/app/src/main/cpp/GakumasLocalify/camera/camera.cpp b/app/src/main/cpp/GakumasLocalify/camera/camera.cpp index 879afe9..1b154f2 100644 --- a/app/src/main/cpp/GakumasLocalify/camera/camera.cpp +++ b/app/src/main/cpp/GakumasLocalify/camera/camera.cpp @@ -16,6 +16,8 @@ namespace GKCamera { UnityResolve::UnityType::Vector2 followLookAtOffset{0, 0}; float offsetMoveStep = 0.008; int followCharaIndex = 0; + float l_sensitivity = 0.5f; + float r_sensitivity = 0.5f; GakumasLocal::Misc::CSEnum bodyPartsEnum("Head", 0xa); // bool rMousePressFlg = false; @@ -59,16 +61,16 @@ namespace GKCamera { } } - void camera_back() { // 后退 + void camera_back(float multiplier = 1.0f) { // 后退 switch (cameraMode) { case CameraMode::FREE: { - baseCamera.set_lon_move(180, LonMoveHState::LonMoveBack); + baseCamera.set_lon_move(180, LonMoveHState::LonMoveBack, multiplier); } break; case CameraMode::FIRST_PERSON: { - firstPersonPosOffset.z -= offsetMoveStep; + firstPersonPosOffset.z -= offsetMoveStep * multiplier; } break; case CameraMode::FOLLOW: { - followPosOffset.z += offsetMoveStep; + followPosOffset.z += offsetMoveStep * multiplier; } } } @@ -86,24 +88,24 @@ namespace GKCamera { } } - void camera_right() { // 向右 + void camera_right(float multiplier = 1.0f) { // 向右 switch (cameraMode) { case CameraMode::FREE: { - baseCamera.set_lon_move(-90); + baseCamera.set_lon_move(-90, LonMoveLeftAndRight, multiplier); } break; case CameraMode::FOLLOW: { // followPosOffset.x -= 0.8; - followLookAtOffset.x -= offsetMoveStep; + followLookAtOffset.x -= offsetMoveStep * multiplier; } default: break; } } - void camera_down() { // 向下 + void camera_down(float multiplier = 1.0f) { // 向下 switch (cameraMode) { case CameraMode::FREE: { - float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel; + float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel * multiplier; for (int i = 0; i < BaseCamera::smoothLevel; i++) { baseCamera.pos.y -= preStep; @@ -112,19 +114,19 @@ namespace GKCamera { } } break; case CameraMode::FIRST_PERSON: { - firstPersonPosOffset.y -= offsetMoveStep; + firstPersonPosOffset.y -= offsetMoveStep * multiplier; } break; case CameraMode::FOLLOW: { // followPosOffset.y -= offsetMoveStep; - followLookAtOffset.y -= offsetMoveStep; + followLookAtOffset.y -= offsetMoveStep * multiplier; } } } - void camera_up() { // 向上 + void camera_up(float multiplier = 1.0f) { // 向上 switch (cameraMode) { case CameraMode::FREE: { - float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel; + float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel * multiplier; for (int i = 0; i < BaseCamera::smoothLevel; i++) { baseCamera.pos.y += preStep; @@ -133,11 +135,11 @@ namespace GKCamera { } } break; case CameraMode::FIRST_PERSON: { - firstPersonPosOffset.y += offsetMoveStep; + firstPersonPosOffset.y += offsetMoveStep * multiplier; } break; case CameraMode::FOLLOW: { // followPosOffset.y += offsetMoveStep; - followLookAtOffset.y += offsetMoveStep; + followLookAtOffset.y += offsetMoveStep * multiplier; } } } @@ -350,14 +352,50 @@ namespace GKCamera { bool k = false; bool j = false; bool l = false; + float thumb_l_right = 0.0f; + float thumb_l_down = 0.0f; + bool thumb_l_button = false; + float thumb_r_right = 0.0f; + float thumb_r_down = 0.0f; + bool thumb_r_button = false; + bool dpad_up = false; + bool dpad_down = false; + bool dpad_left = false; + bool dpad_right = false; + bool a_button = false; + bool b_button = false; + bool x_button = false; + bool y_button = false; + bool lb_button = false; + float lt_button = 0.0f; + bool rb_button = false; + float rt_button = 0.0f; + bool select_button = false; + bool start_button = false; + bool share_button = false; + bool xbox_button = false; bool threadRunning = false; void resetAll() { - auto p = reinterpret_cast(this); - const auto numMembers = sizeof(*this) / sizeof(bool); - for (size_t idx = 0; idx < numMembers; ++idx) { - p[idx] = false; - } + // 获取当前对象的指针并转换为 unsigned char* 类型 + unsigned char* p = reinterpret_cast(this); + + // 遍历对象的每个字节 + for (size_t offset = 0; offset < sizeof(*this); ) { + if (offset + sizeof(bool) <= sizeof(*this) && reinterpret_cast(p + offset) == reinterpret_cast(this) + offset / sizeof(bool)) { + // 如果当前偏移量适用于 bool 类型,则将其设置为 false + *reinterpret_cast(p + offset) = false; + offset += sizeof(bool); + } else if (offset + sizeof(float) <= sizeof(*this) && reinterpret_cast(p + offset) == reinterpret_cast(this) + offset / sizeof(float)) { + // 如果当前偏移量适用于 float 类型,则将其设置为 0.0 + *reinterpret_cast(p + offset) = 0.0f; + offset += sizeof(float); + } else { + // 处理未定义的情况(例如混合类型数组或其他类型成员) + // 可以根据实际情况调整逻辑或添加更多类型检查 + offset += 1; // 跳过一个字节 + } + } } } cameraMoveState; @@ -385,6 +423,24 @@ namespace GKCamera { if (cameraMoveState.k) ChangeLiveFollowCameraOffsetY(-offsetMoveStep); if (cameraMoveState.j) ChangeLiveFollowCameraOffsetX(0.8); if (cameraMoveState.l) ChangeLiveFollowCameraOffsetX(-0.8); + if (std::abs(cameraMoveState.thumb_l_right) > 0.1f) + camera_right(cameraMoveState.thumb_l_right * l_sensitivity); + if (std::abs(cameraMoveState.thumb_l_down) > 0.1f) + camera_back(cameraMoveState.thumb_l_down * l_sensitivity); + if (std::abs(cameraMoveState.thumb_r_right) > 0.1f) + cameraLookat_right(cameraMoveState.thumb_r_right * r_sensitivity); + if (std::abs(cameraMoveState.thumb_r_down) > 0.1f) + cameraLookat_down(cameraMoveState.thumb_r_down * r_sensitivity); + if (std::abs(cameraMoveState.lt_button) > 0.1f) + camera_down(cameraMoveState.lt_button * 0.5f); + if (std::abs(cameraMoveState.rt_button) > 0.1f) + camera_up(cameraMoveState.rt_button * 0.5f); + if (cameraMoveState.dpad_up) ChangeLiveFollowCameraOffsetY(offsetMoveStep); + if (cameraMoveState.dpad_down) ChangeLiveFollowCameraOffsetY(-offsetMoveStep); + if (cameraMoveState.dpad_left) ChangeLiveFollowCameraOffsetX(offsetMoveStep); + if (cameraMoveState.dpad_right) ChangeLiveFollowCameraOffsetX(-offsetMoveStep); + if (cameraMoveState.lb_button) changeCameraFOV(0.5f); + if (cameraMoveState.rb_button) changeCameraFOV(-0.5f); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }).detach(); @@ -446,11 +502,100 @@ namespace GKCamera { } break; case KEY_F: if (message == WM_KEYDOWN) SwitchCameraMode(); break; case KEY_V: if (message == WM_KEYDOWN) SwitchCameraSubMode(); break; + case BTN_A: + cameraMoveState.a_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) r_sensitivity *= 0.8f; + break; + case BTN_B: + cameraMoveState.b_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) r_sensitivity *= 1.2f; + break; + case BTN_X: + cameraMoveState.x_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) l_sensitivity *= 0.8f; + break; + case BTN_Y: + cameraMoveState.y_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) l_sensitivity *= 1.2f; + break; + case BTN_LB: + cameraMoveState.lb_button = message == WM_KEYDOWN; + break; + case BTN_RB: + cameraMoveState.rb_button = message == WM_KEYDOWN; + break; + case BTN_THUMBL: + cameraMoveState.thumb_l_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) reset_camera(); + break; + case BTN_THUMBR: + cameraMoveState.thumb_r_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) { + l_sensitivity = 1.0f; + r_sensitivity = 1.0f; + } + break; + case BTN_SELECT: + cameraMoveState.select_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) SwitchCameraMode(); + break; + case BTN_START: + cameraMoveState.start_button = message == WM_KEYDOWN; + if (message == WM_KEYDOWN) SwitchCameraSubMode(); + break; + case BTN_SHARE: + cameraMoveState.share_button = message == WM_KEYDOWN; + break; + case BTN_XBOX: + cameraMoveState.xbox_button = message == WM_KEYDOWN; + break; + default: break; } } } + void + on_cam_rawinput_joystick(JoystickEvent event) { + int message = event.getMessage(); + float leftStickX = event.getLeftStickX(); + float leftStickY = event.getLeftStickY(); + float rightStickX = event.getRightStickX(); + float rightStickY = event.getRightStickY(); + float leftTrigger = event.getLeftTrigger(); + float rightTrigger = event.getRightTrigger(); + float hatX = event.getHatX(); + float hatY = event.getHatY(); + + cameraMoveState.thumb_l_right = (std::abs(leftStickX) > 0.1f) ? leftStickX : 0; + cameraMoveState.thumb_l_down = (std::abs(leftStickY) > 0.1f) ? leftStickY : 0; + cameraMoveState.thumb_r_right = (std::abs(rightStickX) > 0.1f) ? rightStickX : 0; + cameraMoveState.thumb_r_down = (std::abs(rightStickY) > 0.1f) ? rightStickY : 0; + cameraMoveState.lt_button = (std::abs(leftTrigger) > 0.1f) ? leftTrigger : 0; + cameraMoveState.rt_button = (std::abs(rightTrigger) > 0.1f) ? rightTrigger : 0; + cameraMoveState.dpad_up = hatY == -1.0f; + cameraMoveState.dpad_down = hatY == 1.0f; + cameraMoveState.dpad_left = hatX == -1.0f; + cameraMoveState.dpad_right = hatX == 1.0f; + + if (rightStickX == 1.0f) { + OnRightDown(); + } else if (rightStickX == -1.0f) { + OnLeftDown(); + } + + if (rightStickY == 1.0f) { + OnDownDown(); + } else if (rightStickY == -1.0f) { + OnUpDown(); + } + +// GakumasLocal::Log::InfoFmt( +// "Motion event: action=%d, leftStickX=%.2f, leftStickY=%.2f, rightStickX=%.2f, rightStickY=%.2f, leftTrigger=%.2f, rightTrigger=%.2f, hatX=%.2f, hatY=%.2f", +// message, leftStickX, leftStickY, rightStickX, rightStickY, leftTrigger, +// rightTrigger, hatX, hatY); + } + void initCameraSettings() { reset_camera(); cameraRawInputThread(); diff --git a/app/src/main/cpp/GakumasLocalify/camera/camera.hpp b/app/src/main/cpp/GakumasLocalify/camera/camera.hpp index 0b410e8..d4b035e 100644 --- a/app/src/main/cpp/GakumasLocalify/camera/camera.hpp +++ b/app/src/main/cpp/GakumasLocalify/camera/camera.hpp @@ -1,5 +1,6 @@ #pragma once #include "baseCamera.hpp" +#include "Joystick/JoystickEvent.h" namespace GKCamera { enum class CameraMode { @@ -44,5 +45,6 @@ namespace GKCamera { const bool recordY = false); void on_cam_rawinput_keyboard(int message, int key); + void on_cam_rawinput_joystick(JoystickEvent event); void initCameraSettings(); } diff --git a/app/src/main/cpp/deps/Joystick/JoystickEvent.h b/app/src/main/cpp/deps/Joystick/JoystickEvent.h new file mode 100644 index 0000000..422af8d --- /dev/null +++ b/app/src/main/cpp/deps/Joystick/JoystickEvent.h @@ -0,0 +1,67 @@ +// +// Created by RanKaeder on 2024/6/18. +// + +#ifndef GAKUMAS_LOCALIFY_JOYSTICKEVENT_H +#define GAKUMAS_LOCALIFY_JOYSTICKEVENT_H + +class JoystickEvent { +public: + JoystickEvent(int message, float leftStickX, float leftStickY, float rightStickX, + float rightStickY, float leftTrigger, float rightTrigger, + float hatX, float hatY) + : message(message), leftStickX(leftStickX), leftStickY(leftStickY), + rightStickX(rightStickX), rightStickY(rightStickY), leftTrigger(leftTrigger), + rightTrigger(rightTrigger), hatX(hatX), hatY(hatY) { + } + + // Getter 方法 + int getMessage() const { + return message; + } + + float getLeftStickX() const { + return leftStickX; + } + + float getLeftStickY() const { + return leftStickY; + } + + float getRightStickX() const { + return rightStickX; + } + + float getRightStickY() const { + return rightStickY; + } + + float getLeftTrigger() const { + return leftTrigger; + } + + float getRightTrigger() const { + return rightTrigger; + } + + float getHatX() const { + return hatX; + } + + float getHatY() const { + return hatY; + } + +private: + int message; + float leftStickX; + float leftStickY; + float rightStickX; + float rightStickY; + float leftTrigger; + float rightTrigger; + float hatX; + float hatY; +}; + +#endif //GAKUMAS_LOCALIFY_JOYSTICKEVENT_H \ No newline at end of file diff --git a/app/src/main/cpp/libMarryKotone.cpp b/app/src/main/cpp/libMarryKotone.cpp index 6ce2560..5717925 100644 --- a/app/src/main/cpp/libMarryKotone.cpp +++ b/app/src/main/cpp/libMarryKotone.cpp @@ -9,6 +9,7 @@ #include "xdl.h" #include "GakumasLocalify/camera/camera.hpp" #include "GakumasLocalify/config/Config.hpp" +#include "Joystick/JoystickEvent.h" JavaVM* g_javaVM = nullptr; jclass g_gakumasHookMainClass = nullptr; @@ -87,6 +88,22 @@ Java_io_github_chinosk_gakumas_localify_GakumasHookMain_keyboardEvent(JNIEnv *en } +extern "C" +JNIEXPORT void JNICALL +Java_io_github_chinosk_gakumas_localify_GakumasHookMain_joystickEvent(JNIEnv *env, jclass clazz, + jint action, + jfloat leftStickX, + jfloat leftStickY, + jfloat rightStickX, + jfloat rightStickY, + jfloat leftTrigger, + jfloat rightTrigger, + jfloat hatX, + jfloat hatY) { + JoystickEvent event(action, leftStickX, leftStickY, rightStickX, rightStickY, leftTrigger, rightTrigger, hatX, hatY); + GKCamera::on_cam_rawinput_joystick(event); +} + extern "C" JNIEXPORT void JNICALL Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env, jclass clazz, diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt index 56d12e1..734bcc0 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt @@ -20,6 +20,7 @@ import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.callbacks.XC_LoadPackage import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker import android.view.KeyEvent +import android.view.MotionEvent import android.widget.Toast import com.google.gson.Gson import de.robv.android.xposed.XposedBridge @@ -61,6 +62,50 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { } ) + XposedHelpers.findAndHookMethod( + "android.app.Activity", + lpparam.classLoader, + "dispatchGenericMotionEvent", + MotionEvent::class.java, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + val motionEvent = param.args[0] as MotionEvent + val action = motionEvent.action + + // 左摇杆的X和Y轴 + val leftStickX = motionEvent.getAxisValue(MotionEvent.AXIS_X) + val leftStickY = motionEvent.getAxisValue(MotionEvent.AXIS_Y) + + // 右摇杆的X和Y轴 + val rightStickX = motionEvent.getAxisValue(MotionEvent.AXIS_Z) + val rightStickY = motionEvent.getAxisValue(MotionEvent.AXIS_RZ) + + // 左扳机 + val leftTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_LTRIGGER) + + // 右扳机 + val rightTrigger = motionEvent.getAxisValue(MotionEvent.AXIS_RTRIGGER) + + // 十字键 + val hatX = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X) + val hatY = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y) + + // 处理摇杆和扳机事件 + joystickEvent( + action, + leftStickX, + leftStickY, + rightStickX, + rightStickY, + leftTrigger, + rightTrigger, + hatX, + hatY + ) + } + } + ) + val appActivityClass = XposedHelpers.findClass("android.app.Activity", lpparam.classLoader) XposedBridge.hookAllMethods(appActivityClass, "onStart", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { @@ -256,6 +301,18 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { @JvmStatic external fun keyboardEvent(keyCode: Int, action: Int) @JvmStatic + external fun joystickEvent( + action: Int, + leftStickX: Float, + leftStickY: Float, + rightStickX: Float, + rightStickY: Float, + leftTrigger: Float, + rightTrigger: Float, + hatX: Float, + hatY: Float + ) + @JvmStatic external fun loadConfig(configJsonStr: String) @JvmStatic