Skip to content

Commit d95b75a

Browse files
committed
fix(android): preserve existing input hook
1 parent 0ec422d commit d95b75a

1 file changed

Lines changed: 78 additions & 31 deletions

File tree

‎StArray.ModManager.Android/UI/ImGuiInputHandler.cs‎

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.CompilerServices;
12
using System.Runtime.InteropServices;
23
using ImGuiNET;
34
using StArray.ModManager.Android.Native;
@@ -67,42 +68,88 @@ public static void InstallInputHooks()
6768
IsInitialized = true;
6869
}
6970

70-
/// <summary>在 Android 输入消费完成后读取本次输出事件。</summary>
71-
[NativeHook("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE",
72-
Convention = CallingConvention.Cdecl)]
73-
public unsafe static int OnConsume(
74-
void* thiz,
75-
void* factory,
76-
bool consumeBatches,
77-
long frameTime,
78-
uint* outSeq,
79-
void** outEvent)
71+
/*
72+
/// <summary>触摸事件 Hook 回调</summary>
73+
[NativeHook("libinput.so","_ZN7android13InputConsumer14consumeSamplesEPNS_26InputEventFactoryInterfaceERNS0_5BatchEmPjPPNS_10InputEventE")]
74+
public unsafe static long OnConsumeSamples(void* thiz,void* factory, IntPtr batch,
75+
ulong count, uint* outSeq, void** outEvent)
8076
{
81-
var result = OnConsumeOriginal(
82-
thiz,
83-
factory,
84-
consumeBatches,
85-
frameTime,
86-
outSeq,
87-
outEvent);
88-
if (outEvent != null && *outEvent != null)
89-
DispatchInputEvent(new IntPtr(*outEvent));
77+
var result = OnConsumeSamplesOriginal(thiz,factory, batch, count, outSeq, outEvent);
78+
if (IsInitialized && *outEvent != null) ImGuiImplAndroid.HandleInputEvent(new IntPtr(*outEvent));
9079
return result;
9180
}
92-
93-
/// <summary>
94-
/// 把一个原生输入事件同时送往 ImGui 和 <see cref="InputEvents"/> 订阅方。
95-
/// </summary>
96-
/// <remarks>
97-
/// 输入广播不依赖 ImGui 上下文是否已经初始化;这样异步输入 Mod 可以在
98-
/// 菜单、暂停和非游玩阶段继续收到原始事件并自行决定是否消费。
99-
/// </remarks>
100-
private static void DispatchInputEvent(IntPtr inputEvent)
81+
82+
[NativeHook("libinput.so","_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE")]
83+
public unsafe static long OnConsume(void* thiz, void* factory, bool consumeBatches, ulong frameTime, uint* outSeq, void** outEvent)
10184
{
85+
var result = OnConsumeOriginal(thiz, factory, consumeBatches, frameTime, outSeq, outEvent);
86+
if (IsInitialized && *outEvent != null) ImGuiImplAndroid.HandleInputEvent(new IntPtr(*outEvent));
87+
return result;
88+
}*/
89+
90+
[NativeHook("GetInitializeMotionEventAddress")]
91+
public unsafe static bool OnInitializeMotionEvent(void* @event, void* message)
92+
{
93+
var result = OnInitializeMotionEventOriginal(@event, message);
94+
var x = AndroidInput.AMotionEvent_getX(new(@event), 0);
95+
var y = AndroidInput.AMotionEvent_getY(new(@event), 0);
10296
if (InputEvents.HasSubscribers)
103-
InputEvents.RaiseFrom(inputEvent);
104-
if (IsInitialized)
105-
ImGuiImplAndroid.HandleInputEvent(inputEvent);
97+
InputEvents.RaiseFrom(new IntPtr(@event));
98+
ImGuiImplAndroid.HandleInputEvent(new IntPtr(@event));
99+
return result;
100+
}
101+
102+
private static nint GetInitializeMotionEventAddress()
103+
{
104+
byte?[] sig = NativeFuncResolver.ParseHexPattern(
105+
"e8 0f 19 fc fd 7b 01 a9 fc 6f 02 a9 fa 67 03 a9 " +
106+
"f8 5f 04 a9 f6 57 05 a9 f4 4f 06 a9 fd 43 00 91");
107+
var r = new NativeFuncResolver("/system/lib64/libinput.so");
108+
long rva = r.FindSymbolRva("_ZN7android13InputConsumer21initializeMotionEventEPNS_11MotionEventEPKNS_12InputMessageE");
109+
try
110+
{
111+
if (rva < 0)
112+
{
113+
var text = r.TextBytes;
114+
long textAddr = r.TextBaseAddress;
115+
int pos = 0;
116+
while ((pos = NativeFuncResolver.Search(text, sig, pos)) >= 0)
117+
{
118+
int ctxEnd = Math.Min(pos + 60, text.Length);
119+
bool hasMrs = false, hasLdr = false;
120+
for (int j = pos + 32; j <= ctxEnd - 4; j += 4)
121+
{
122+
int inst = BitConverter.ToInt32(text.AsSpan(j));
123+
if (!hasMrs && (inst & 0xffffffe0) == 0xd53bd040)
124+
hasMrs = true;
125+
if (!hasLdr && (inst & 0xffe003e0) == 0xb9400020)
126+
{
127+
int imm12 = (inst >> 10) & 0xfff;
128+
if (imm12 * 4 == 0xc) hasLdr = true;
129+
}
130+
if (hasMrs && hasLdr) break;
131+
}
132+
if (hasMrs && hasLdr)
133+
{
134+
rva = textAddr + pos;
135+
if (pos >= 4)
136+
{
137+
int prev = BitConverter.ToInt32(text.AsSpan(pos - 4));
138+
if (prev == unchecked((int)0xd503233f)) rva -= 4;
139+
}
140+
break;
141+
}
142+
pos++;
143+
}
144+
if (rva < 0) throw new KeyNotFoundException("initializeMotionEvent not found by signature.");
145+
}
146+
}
147+
catch (Exception ex)
148+
{
149+
Logger.Error(nameof(ImGuiInputHandler), ex.ToString());
150+
}
151+
r.Load();
152+
return r.GetFuncPtr(rva);
106153
}
107154

108155
private static JavaClass? s_utilsClass;

0 commit comments

Comments
 (0)