Skip to content

Commit bf93b26

Browse files
committed
feat: add Shizuku support for non-root input backend and enhance touch handling
1 parent 6223d76 commit bf93b26

12 files changed

Lines changed: 763 additions & 48 deletions

File tree

app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,8 @@ dependencies {
114114
// Debug-only: keep tooling preview off the release build
115115
debugImplementation 'androidx.compose.ui:ui-tooling-preview'
116116
debugImplementation 'androidx.compose.ui:ui-tooling'
117+
118+
// Optional non-root input backend (Shizuku)
119+
implementation 'dev.rikka.shizuku:api:13.1.5'
120+
implementation 'dev.rikka.shizuku:provider:13.1.5'
117121
}

app/src/main/AndroidManifest.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
<!-- Network access for GitHub-backed model store -->
1515
<uses-permission android:name="android.permission.INTERNET"/>
16+
17+
<!-- Optional non-root input backend (Shizuku) -->
18+
<uses-permission android:name="moe.shizuku.manager.permission.API_V23"/>
1619

1720
<!-- Vulkan GPU feature — optional so the app still runs on devices without Vulkan -->
1821
<uses-feature android:name="android.hardware.vulkan.level" android:version="1" android:required="false"/>
@@ -58,6 +61,18 @@
5861
android:exported="false"
5962
android:foregroundServiceType="mediaProjection" />
6063

64+
<provider
65+
android:name="rikka.shizuku.ShizukuProvider"
66+
android:authorities="${applicationId}.shizuku"
67+
android:enabled="true"
68+
android:exported="true"
69+
android:multiprocess="false"
70+
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
71+
72+
<meta-data
73+
android:name="moe.shizuku.client.V3_SUPPORT"
74+
android:value="true" />
75+
6176
</application>
6277

6378
</manifest>

app/src/main/cpp/aimbot/aimbot_controller.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ void AimbotController::sanitizeMovement(float dx, float dy, float distance,
450450
}
451451

452452
void AimbotController::applyMovement(float moveX, float moveY, const UnifiedSettings& settings) {
453+
m_touch->setBackend(settings.touchBackend == 1 ? TouchBackend::SHIZUKU : TouchBackend::UINPUT);
454+
453455
const float blend = m_isAiming ? 0.72f : 1.0f;
454456
moveX = m_prevMoveX * (1.0f - blend) + moveX * blend;
455457
moveY = m_prevMoveY * (1.0f - blend) + moveY * blend;

app/src/main/cpp/aimbot/aimbot_controller.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../input/touch_helper.h"
77
#include "target_tracker.h"
88
#include <mutex>
9+
#include <condition_variable>
910
#include <atomic>
1011
#include <thread>
1112
#include <vector>
@@ -48,6 +49,8 @@ class AimbotController {
4849
std::atomic<bool> m_running;
4950
std::thread m_aimThread;
5051
std::mutex m_trackerMutex;
52+
std::condition_variable m_targetUpdateCv;
53+
std::atomic<uint64_t> m_targetUpdateSeq;
5154

5255
void aimLoop();
5356

app/src/main/cpp/esp_jni.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,8 @@ Java_com_aimbuddy_MainActivity_nativeInit(JNIEnv* env, jobject thiz,
431431
// Create TouchHelper and AimbotController (but DON'T init touch yet)
432432
// Touch init happens in nativeInitAimbot() AFTER root permissions are set
433433
g_touchHelper = std::make_unique<TouchHelper>();
434+
g_touchHelper->setJniBridge(g_jvm, env, thiz);
435+
g_touchHelper->setBackend(g_settings.touchBackend == 1 ? TouchBackend::SHIZUKU : TouchBackend::UINPUT);
434436
g_touchHelper->setScreenSize(screenWidth, screenHeight);
435437

436438
// Create aimbot controller with touch helper
@@ -633,8 +635,11 @@ Java_com_aimbuddy_MainActivity_nativeInitAimbot(JNIEnv* env, jobject thiz) {
633635
if (!g_touchHelper) {
634636
LOGE("TouchHelper is null, creating new one");
635637
g_touchHelper = std::make_unique<TouchHelper>();
636-
g_touchHelper->setScreenSize(g_screenWidth, g_screenHeight);
637638
}
639+
640+
g_touchHelper->setJniBridge(g_jvm, env, thiz);
641+
g_touchHelper->setBackend(g_settings.touchBackend == 1 ? TouchBackend::SHIZUKU : TouchBackend::UINPUT);
642+
g_touchHelper->setScreenSize(g_screenWidth, g_screenHeight);
638643

639644
// THIS is where we actually init the touch device (needs root)
640645
if (g_touchHelper->init()) {
@@ -653,11 +658,35 @@ Java_com_aimbuddy_MainActivity_nativeInitAimbot(JNIEnv* env, jobject thiz) {
653658
return JNI_TRUE;
654659
}
655660

656-
LOGE("TouchHelper init FAILED!");
657-
LOGE("Check: 1) Root granted 2) /dev/uinput exists 3) /dev/input/event* accessible");
661+
LOGE("TouchHelper init FAILED for backend=%d", g_settings.touchBackend);
662+
LOGE("Check: uinput requires root, Shizuku requires active service + permission");
658663
return JNI_FALSE;
659664
}
660665

666+
JNIEXPORT void JNICALL
667+
Java_com_aimbuddy_MainActivity_nativeSetTouchBackend(JNIEnv* /* env */, jobject /* thiz */, jint backend) {
668+
const int clamped = std::max(0, std::min(1, static_cast<int>(backend)));
669+
g_settings.touchBackend = clamped;
670+
g_settings.validate();
671+
672+
if (g_touchHelper) {
673+
g_touchHelper->setBackend(clamped == 1 ? TouchBackend::SHIZUKU : TouchBackend::UINPUT);
674+
}
675+
LOGI("Touch backend set to %d", clamped);
676+
}
677+
678+
JNIEXPORT jint JNICALL
679+
Java_com_aimbuddy_MainActivity_nativeGetTouchBackend(JNIEnv* /* env */, jobject /* thiz */) {
680+
return g_settings.touchBackend;
681+
}
682+
683+
JNIEXPORT void JNICALL
684+
Java_com_aimbuddy_MainActivity_nativeSetShizukuBridgeAvailable(JNIEnv* /* env */, jobject /* thiz */, jboolean available) {
685+
if (g_touchHelper) {
686+
g_touchHelper->setShizukuBridgeAvailable(available == JNI_TRUE);
687+
}
688+
}
689+
661690
JNIEXPORT void JNICALL
662691
Java_com_aimbuddy_MainActivity_nativeSetModelPaths(JNIEnv* env, jobject thiz,
663692
jstring paramPath,

app/src/main/cpp/input/touch_helper.cpp

Lines changed: 211 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,40 +586,249 @@ void touchInputStop() {
586586

587587
} // namespace
588588

589-
TouchHelper::TouchHelper() = default;
589+
TouchHelper::TouchHelper()
590+
: backend_(TouchBackend::UINPUT)
591+
, initialized_(false)
592+
, shizukuBridgeAvailable_(false)
593+
, javaVm_(nullptr)
594+
, activityClassGlobal_(nullptr)
595+
, shizukuMoveMethod_(nullptr)
596+
, shizukuUpMethod_(nullptr) {}
590597

591598
TouchHelper::~TouchHelper() {
599+
if (javaVm_ && activityClassGlobal_) {
600+
JNIEnv* env = nullptr;
601+
if (javaVm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_OK && env) {
602+
env->DeleteGlobalRef(activityClassGlobal_);
603+
}
604+
}
592605
shutdown();
593606
}
594607

608+
void TouchHelper::setBackend(TouchBackend backend) {
609+
if (backend_ == backend) {
610+
return;
611+
}
612+
releaseActiveTouch();
613+
shutdownUinput();
614+
initialized_ = false;
615+
backend_ = backend;
616+
}
617+
618+
void TouchHelper::setJniBridge(JavaVM* vm, JNIEnv* env, jobject activityInstance) {
619+
javaVm_ = vm;
620+
if (!env || !activityInstance) {
621+
return;
622+
}
623+
624+
if (activityClassGlobal_) {
625+
env->DeleteGlobalRef(activityClassGlobal_);
626+
activityClassGlobal_ = nullptr;
627+
}
628+
629+
jclass localClass = env->GetObjectClass(activityInstance);
630+
if (!localClass) {
631+
return;
632+
}
633+
activityClassGlobal_ = static_cast<jclass>(env->NewGlobalRef(localClass));
634+
env->DeleteLocalRef(localClass);
635+
636+
shizukuMoveMethod_ = nullptr;
637+
shizukuUpMethod_ = nullptr;
638+
}
639+
640+
void TouchHelper::setShizukuBridgeAvailable(bool available) {
641+
shizukuBridgeAvailable_ = available;
642+
if (!available && backend_ == TouchBackend::SHIZUKU) {
643+
shutdown();
644+
}
645+
}
646+
595647
bool TouchHelper::init() {
596-
if (g_touchStart) {
648+
if (initialized_) {
597649
return true;
598650
}
599651

652+
if (backend_ == TouchBackend::SHIZUKU) {
653+
initialized_ = initShizuku();
654+
return initialized_;
655+
}
656+
657+
initialized_ = initUinput();
658+
return initialized_;
659+
}
660+
661+
bool TouchHelper::initUinput() {
662+
if (g_touchStart) {
663+
return true;
664+
}
600665
touchInputStart();
601666
return g_touchStart;
602667
}
603668

669+
bool TouchHelper::initShizuku() {
670+
return shizukuBridgeAvailable_;
671+
}
672+
673+
void TouchHelper::releaseActiveTouch() {
674+
if (!initialized_) {
675+
return;
676+
}
677+
678+
if (backend_ == TouchBackend::SHIZUKU) {
679+
callShizukuUp();
680+
return;
681+
}
682+
683+
sendTouchUp();
684+
}
685+
604686
void TouchHelper::setScreenSize(int width, int height) {
605687
updateRes(width, height);
606688
}
607689

608690
void TouchHelper::touchDown(int slot, float x, float y) {
609691
(void)slot;
692+
if (!initialized_ && !init()) {
693+
return;
694+
}
695+
696+
if (backend_ == TouchBackend::SHIZUKU) {
697+
if (!callShizukuMove(x, y, true)) {
698+
initialized_ = false;
699+
}
700+
return;
701+
}
610702
sendTouchMove(static_cast<int>(x), static_cast<int>(y));
611703
}
612704

613705
void TouchHelper::touchMove(int slot, float x, float y) {
614706
(void)slot;
707+
if (!initialized_ && !init()) {
708+
return;
709+
}
710+
711+
if (backend_ == TouchBackend::SHIZUKU) {
712+
if (!callShizukuMove(x, y, false)) {
713+
initialized_ = false;
714+
}
715+
return;
716+
}
615717
sendTouchMove(static_cast<int>(x), static_cast<int>(y));
616718
}
617719

618720
void TouchHelper::touchUp(int slot) {
619721
(void)slot;
722+
if (!initialized_) {
723+
return;
724+
}
725+
726+
if (backend_ == TouchBackend::SHIZUKU) {
727+
if (!callShizukuUp()) {
728+
initialized_ = false;
729+
}
730+
return;
731+
}
620732
sendTouchUp();
621733
}
622734

623735
void TouchHelper::shutdown() {
736+
releaseActiveTouch();
737+
shutdownUinput();
738+
initialized_ = false;
739+
}
740+
741+
bool TouchHelper::isInitialized() const {
742+
return initialized_;
743+
}
744+
745+
void TouchHelper::shutdownUinput() {
624746
touchInputStop();
625747
}
748+
749+
bool TouchHelper::ensureJniMethods(JNIEnv* env) {
750+
if (!env || !activityClassGlobal_) {
751+
return false;
752+
}
753+
754+
if (!shizukuMoveMethod_) {
755+
shizukuMoveMethod_ = env->GetStaticMethodID(
756+
activityClassGlobal_,
757+
"nativeInjectShizukuAimMove",
758+
"(FFZ)Z"
759+
);
760+
}
761+
if (!shizukuUpMethod_) {
762+
shizukuUpMethod_ = env->GetStaticMethodID(
763+
activityClassGlobal_,
764+
"nativeInjectShizukuAimUp",
765+
"()Z"
766+
);
767+
}
768+
769+
return shizukuMoveMethod_ && shizukuUpMethod_;
770+
}
771+
772+
bool TouchHelper::callShizukuMove(float x, float y, bool isFirst) {
773+
if (!javaVm_ || !shizukuBridgeAvailable_) {
774+
return false;
775+
}
776+
777+
JNIEnv* env = nullptr;
778+
bool attached = false;
779+
if (javaVm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
780+
if (javaVm_->AttachCurrentThread(&env, nullptr) != JNI_OK) {
781+
return false;
782+
}
783+
attached = true;
784+
}
785+
786+
bool ok = false;
787+
if (ensureJniMethods(env)) {
788+
const jboolean result = env->CallStaticBooleanMethod(
789+
activityClassGlobal_,
790+
shizukuMoveMethod_,
791+
static_cast<jfloat>(x),
792+
static_cast<jfloat>(y),
793+
static_cast<jboolean>(isFirst)
794+
);
795+
ok = (result == JNI_TRUE) && !env->ExceptionCheck();
796+
if (env->ExceptionCheck()) {
797+
env->ExceptionClear();
798+
}
799+
}
800+
801+
if (attached) {
802+
javaVm_->DetachCurrentThread();
803+
}
804+
return ok;
805+
}
806+
807+
bool TouchHelper::callShizukuUp() {
808+
if (!javaVm_ || !shizukuBridgeAvailable_) {
809+
return false;
810+
}
811+
812+
JNIEnv* env = nullptr;
813+
bool attached = false;
814+
if (javaVm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
815+
if (javaVm_->AttachCurrentThread(&env, nullptr) != JNI_OK) {
816+
return false;
817+
}
818+
attached = true;
819+
}
820+
821+
bool ok = false;
822+
if (ensureJniMethods(env)) {
823+
const jboolean result = env->CallStaticBooleanMethod(activityClassGlobal_, shizukuUpMethod_);
824+
ok = (result == JNI_TRUE) && !env->ExceptionCheck();
825+
if (env->ExceptionCheck()) {
826+
env->ExceptionClear();
827+
}
828+
}
829+
830+
if (attached) {
831+
javaVm_->DetachCurrentThread();
832+
}
833+
return ok;
834+
}

0 commit comments

Comments
 (0)