增加 Xbox 手柄支持

This commit is contained in:
楪蘭楓 2024-06-20 18:53:25 +08:00
parent 64f147586f
commit 7345a4bbe6
8 changed files with 326 additions and 25 deletions

View File

@ -24,3 +24,16 @@
#define WM_KEYDOWN 0 #define WM_KEYDOWN 0
#define WM_KEYUP 1 #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

View File

@ -62,14 +62,14 @@ namespace BaseCamera {
return lookAt; 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 radian = (verticalAngle + vertanglePlus) * M_PI / 180;
auto radianH = (double)horizontalAngle * M_PI / 180; auto radianH = (double)horizontalAngle * M_PI / 180;
auto f_step = cos(radian) * moveStep * cos(radianH) / smoothLevel; // ↑↓ auto f_step = cos(radian) * moveStep * cos(radianH) / smoothLevel * multiplier; // ↑↓
auto l_step = sin(radian) * moveStep * cos(radianH) / smoothLevel; // ←→ 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 = 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) switch (moveState)
{ {

View File

@ -30,7 +30,7 @@ namespace BaseCamera {
void setPos(float x, float y, float z); void setPos(float x, float y, float z);
void setLookAt(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 updateVertLook();
void setHoriLook(float vertangle); void setHoriLook(float vertangle);

View File

@ -16,6 +16,8 @@ namespace GKCamera {
UnityResolve::UnityType::Vector2 followLookAtOffset{0, 0}; UnityResolve::UnityType::Vector2 followLookAtOffset{0, 0};
float offsetMoveStep = 0.008; float offsetMoveStep = 0.008;
int followCharaIndex = 0; int followCharaIndex = 0;
float l_sensitivity = 0.5f;
float r_sensitivity = 0.5f;
GakumasLocal::Misc::CSEnum bodyPartsEnum("Head", 0xa); GakumasLocal::Misc::CSEnum bodyPartsEnum("Head", 0xa);
// bool rMousePressFlg = false; // bool rMousePressFlg = false;
@ -59,16 +61,16 @@ namespace GKCamera {
} }
} }
void camera_back() { // 后退 void camera_back(float multiplier = 1.0f) { // 后退
switch (cameraMode) { switch (cameraMode) {
case CameraMode::FREE: { case CameraMode::FREE: {
baseCamera.set_lon_move(180, LonMoveHState::LonMoveBack); baseCamera.set_lon_move(180, LonMoveHState::LonMoveBack, multiplier);
} break; } break;
case CameraMode::FIRST_PERSON: { case CameraMode::FIRST_PERSON: {
firstPersonPosOffset.z -= offsetMoveStep; firstPersonPosOffset.z -= offsetMoveStep * multiplier;
} break; } break;
case CameraMode::FOLLOW: { 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) { switch (cameraMode) {
case CameraMode::FREE: { case CameraMode::FREE: {
baseCamera.set_lon_move(-90); baseCamera.set_lon_move(-90, LonMoveLeftAndRight, multiplier);
} break; } break;
case CameraMode::FOLLOW: { case CameraMode::FOLLOW: {
// followPosOffset.x -= 0.8; // followPosOffset.x -= 0.8;
followLookAtOffset.x -= offsetMoveStep; followLookAtOffset.x -= offsetMoveStep * multiplier;
} }
default: default:
break; break;
} }
} }
void camera_down() { // 向下 void camera_down(float multiplier = 1.0f) { // 向下
switch (cameraMode) { switch (cameraMode) {
case CameraMode::FREE: { case CameraMode::FREE: {
float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel; float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel * multiplier;
for (int i = 0; i < BaseCamera::smoothLevel; i++) { for (int i = 0; i < BaseCamera::smoothLevel; i++) {
baseCamera.pos.y -= preStep; baseCamera.pos.y -= preStep;
@ -112,19 +114,19 @@ namespace GKCamera {
} }
} break; } break;
case CameraMode::FIRST_PERSON: { case CameraMode::FIRST_PERSON: {
firstPersonPosOffset.y -= offsetMoveStep; firstPersonPosOffset.y -= offsetMoveStep * multiplier;
} break; } break;
case CameraMode::FOLLOW: { case CameraMode::FOLLOW: {
// followPosOffset.y -= offsetMoveStep; // followPosOffset.y -= offsetMoveStep;
followLookAtOffset.y -= offsetMoveStep; followLookAtOffset.y -= offsetMoveStep * multiplier;
} }
} }
} }
void camera_up() { // 向上 void camera_up(float multiplier = 1.0f) { // 向上
switch (cameraMode) { switch (cameraMode) {
case CameraMode::FREE: { case CameraMode::FREE: {
float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel; float preStep = BaseCamera::moveStep / BaseCamera::smoothLevel * multiplier;
for (int i = 0; i < BaseCamera::smoothLevel; i++) { for (int i = 0; i < BaseCamera::smoothLevel; i++) {
baseCamera.pos.y += preStep; baseCamera.pos.y += preStep;
@ -133,11 +135,11 @@ namespace GKCamera {
} }
} break; } break;
case CameraMode::FIRST_PERSON: { case CameraMode::FIRST_PERSON: {
firstPersonPosOffset.y += offsetMoveStep; firstPersonPosOffset.y += offsetMoveStep * multiplier;
} break; } break;
case CameraMode::FOLLOW: { case CameraMode::FOLLOW: {
// followPosOffset.y += offsetMoveStep; // followPosOffset.y += offsetMoveStep;
followLookAtOffset.y += offsetMoveStep; followLookAtOffset.y += offsetMoveStep * multiplier;
} }
} }
} }
@ -350,13 +352,49 @@ namespace GKCamera {
bool k = false; bool k = false;
bool j = false; bool j = false;
bool l = 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; bool threadRunning = false;
void resetAll() { void resetAll() {
auto p = reinterpret_cast<bool*>(this); // 获取当前对象的指针并转换为 unsigned char* 类型
const auto numMembers = sizeof(*this) / sizeof(bool); unsigned char* p = reinterpret_cast<unsigned char*>(this);
for (size_t idx = 0; idx < numMembers; ++idx) {
p[idx] = false; // 遍历对象的每个字节
for (size_t offset = 0; offset < sizeof(*this); ) {
if (offset + sizeof(bool) <= sizeof(*this) && reinterpret_cast<bool*>(p + offset) == reinterpret_cast<bool*>(this) + offset / sizeof(bool)) {
// 如果当前偏移量适用于 bool 类型,则将其设置为 false
*reinterpret_cast<bool*>(p + offset) = false;
offset += sizeof(bool);
} else if (offset + sizeof(float) <= sizeof(*this) && reinterpret_cast<float*>(p + offset) == reinterpret_cast<float*>(this) + offset / sizeof(float)) {
// 如果当前偏移量适用于 float 类型,则将其设置为 0.0
*reinterpret_cast<float*>(p + offset) = 0.0f;
offset += sizeof(float);
} else {
// 处理未定义的情况(例如混合类型数组或其他类型成员)
// 可以根据实际情况调整逻辑或添加更多类型检查
offset += 1; // 跳过一个字节
}
} }
} }
} cameraMoveState; } cameraMoveState;
@ -385,6 +423,24 @@ namespace GKCamera {
if (cameraMoveState.k) ChangeLiveFollowCameraOffsetY(-offsetMoveStep); if (cameraMoveState.k) ChangeLiveFollowCameraOffsetY(-offsetMoveStep);
if (cameraMoveState.j) ChangeLiveFollowCameraOffsetX(0.8); if (cameraMoveState.j) ChangeLiveFollowCameraOffsetX(0.8);
if (cameraMoveState.l) 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)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
}).detach(); }).detach();
@ -446,11 +502,100 @@ namespace GKCamera {
} break; } break;
case KEY_F: if (message == WM_KEYDOWN) SwitchCameraMode(); break; case KEY_F: if (message == WM_KEYDOWN) SwitchCameraMode(); break;
case KEY_V: if (message == WM_KEYDOWN) SwitchCameraSubMode(); 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; 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() { void initCameraSettings() {
reset_camera(); reset_camera();
cameraRawInputThread(); cameraRawInputThread();

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "baseCamera.hpp" #include "baseCamera.hpp"
#include "Joystick/JoystickEvent.h"
namespace GKCamera { namespace GKCamera {
enum class CameraMode { enum class CameraMode {
@ -44,5 +45,6 @@ namespace GKCamera {
const bool recordY = false); const bool recordY = false);
void on_cam_rawinput_keyboard(int message, int key); void on_cam_rawinput_keyboard(int message, int key);
void on_cam_rawinput_joystick(JoystickEvent event);
void initCameraSettings(); void initCameraSettings();
} }

View File

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

View File

@ -9,6 +9,7 @@
#include "xdl.h" #include "xdl.h"
#include "GakumasLocalify/camera/camera.hpp" #include "GakumasLocalify/camera/camera.hpp"
#include "GakumasLocalify/config/Config.hpp" #include "GakumasLocalify/config/Config.hpp"
#include "Joystick/JoystickEvent.h"
JavaVM* g_javaVM = nullptr; JavaVM* g_javaVM = nullptr;
jclass g_gakumasHookMainClass = 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" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env, jclass clazz, Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env, jclass clazz,

View File

@ -20,6 +20,7 @@ import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker import io.github.chinosk.gakumas.localify.hookUtils.FilesChecker
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent
import android.widget.Toast import android.widget.Toast
import com.google.gson.Gson import com.google.gson.Gson
import de.robv.android.xposed.XposedBridge 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) val appActivityClass = XposedHelpers.findClass("android.app.Activity", lpparam.classLoader)
XposedBridge.hookAllMethods(appActivityClass, "onStart", object : XC_MethodHook() { XposedBridge.hookAllMethods(appActivityClass, "onStart", object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) { override fun beforeHookedMethod(param: MethodHookParam) {
@ -256,6 +301,18 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
@JvmStatic @JvmStatic
external fun keyboardEvent(keyCode: Int, action: Int) external fun keyboardEvent(keyCode: Int, action: Int)
@JvmStatic @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) external fun loadConfig(configJsonStr: String)
@JvmStatic @JvmStatic