Skip to content

Commit b004e5c

Browse files
authored
针对华为非鸿蒙next平板的修复和其它增强 (qiin2333#179)
1 parent 1fad68b commit b004e5c

File tree

6 files changed

+386
-1
lines changed

6 files changed

+386
-1
lines changed

app/src/main/java/com/limelight/Game.java

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@
102102
import java.security.cert.CertificateFactory;
103103
import java.security.cert.X509Certificate;
104104
import java.util.ArrayList;
105+
import java.util.HashSet;
105106
import java.util.List;
106107
import java.util.HashMap;
107108
import java.util.Map;
108109
import java.util.Locale;
110+
import java.util.Set;
109111

110112
import com.limelight.services.KeyboardAccessibilityService;
111113

@@ -354,6 +356,14 @@ private void stopAndUnbindUsbDriverService() {
354356

355357
private ExternalDisplayManager externalDisplayManager;
356358

359+
private float fakeScrollInitialY = -1;
360+
private float scrollTotal = 0;
361+
private long lastMouseHoverTime = 0; // 记录最后一次鼠标活跃的时间
362+
private boolean waitRelease = false;
363+
private boolean detectScrolling = false;
364+
private boolean detectMouseMiddle = false;
365+
private boolean detectMouseMiddleDown = false;
366+
357367
@Override
358368
protected void onCreate(Bundle savedInstanceState) {
359369
super.onCreate(savedInstanceState);
@@ -2097,6 +2107,11 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
20972107
return handleKeyDown(event) || super.onKeyDown(keyCode, event);
20982108
}
20992109

2110+
private final Set<Integer> pressedKeys = new HashSet<>();
2111+
// 0代表未按下,1代表按下esc,2代表按下自定义组合键
2112+
private int escState = 0; // 0 = 空闲,1 = ESC已按下,2 = 已进入组合键
2113+
private Handler handler = new Handler(Looper.getMainLooper());
2114+
private Runnable escConfirmRunnable;
21002115
@Override
21012116
public boolean handleKeyDown(KeyEvent event) {
21022117
switch (event.getKeyCode()) {
@@ -2105,6 +2120,10 @@ public boolean handleKeyDown(KeyEvent event) {
21052120
case KeyEvent.KEYCODE_APP_SWITCH:
21062121
// 如果是系统导航键,则跳过我们的去重逻辑,
21072122
// 让事件继续被正常处理。
2123+
case KeyEvent.KEYCODE_VOLUME_UP:
2124+
case KeyEvent.KEYCODE_VOLUME_DOWN:
2125+
case KeyEvent.KEYCODE_VOLUME_MUTE:
2126+
case KeyEvent.KEYCODE_POWER:
21082127
break;
21092128
default:
21102129
// 只有当事件不是来自服务、服务正在运行、且事件源不是虚拟键盘(即来自物理键盘)时,
@@ -2119,6 +2138,76 @@ public boolean handleKeyDown(KeyEvent event) {
21192138
break;
21202139
}
21212140

2141+
// 自定义组合键,只能其它+esc,esc+其它时,esc抬起时其它才会down
2142+
int keyCode = event.getKeyCode();
2143+
pressedKeys.add(keyCode);
2144+
if (prefConfig.enableCustomKeyMap) {
2145+
if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
2146+
escState = 1;
2147+
// Log.d("debug", "Esc: Down");
2148+
// 启动延迟判断是否是单独的ESC键
2149+
escConfirmRunnable = () -> {
2150+
if (escState == 1) {
2151+
// Log.d("debug", "Esc: Confirmed as Single");
2152+
short translated = keyboardTranslator.translate(KeyEvent.KEYCODE_ESCAPE, event.getDeviceId());
2153+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2154+
escState = 0;
2155+
}
2156+
};
2157+
handler.postDelayed(escConfirmRunnable, 200); // 延迟判断
2158+
return true;
2159+
}
2160+
2161+
if (escState == 1) {
2162+
// 若在ESC后检测到自定义键按下,取消ESC单键判断
2163+
handler.removeCallbacks(escConfirmRunnable);
2164+
2165+
if (keyCode == KeyEvent.KEYCODE_Q) {
2166+
// Log.d("debug", "Esc + Q: Down");
2167+
escState = 2;
2168+
return true;
2169+
}
2170+
else if (keyCode >= KeyEvent.KEYCODE_1 && keyCode <= KeyEvent.KEYCODE_9) {
2171+
// Log.d("debug", "Esc + num: Down");
2172+
escState = 2;
2173+
int fKeyCode = KeyEvent.KEYCODE_F1 + (keyCode - KeyEvent.KEYCODE_1);
2174+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2175+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2176+
return true;
2177+
}
2178+
else if (keyCode == KeyEvent.KEYCODE_0) {
2179+
// Log.d("debug", "Esc + 0: Down -> F10");
2180+
escState = 2;
2181+
int fKeyCode = KeyEvent.KEYCODE_F10;
2182+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2183+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2184+
return true;
2185+
}
2186+
else if (keyCode == KeyEvent.KEYCODE_MINUS) {
2187+
// Log.d("debug", "Esc + -: Down -> F11");
2188+
escState = 2;
2189+
int fKeyCode = KeyEvent.KEYCODE_F11;
2190+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2191+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2192+
return true;
2193+
}
2194+
else if (keyCode == KeyEvent.KEYCODE_EQUALS) {
2195+
// Log.d("debug", "Esc + =: Down -> F12");
2196+
escState = 2;
2197+
int fKeyCode = KeyEvent.KEYCODE_F12;
2198+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2199+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2200+
return true;
2201+
}
2202+
else{
2203+
// 非自定义组合键,不做处理
2204+
short translated = keyboardTranslator.translate(KeyEvent.KEYCODE_ESCAPE, event.getDeviceId());
2205+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2206+
escState = 0;
2207+
}
2208+
}
2209+
}
2210+
21222211
// Pass-through virtual navigation keys
21232212
if ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
21242213
return false;
@@ -2144,6 +2233,17 @@ public boolean handleKeyDown(KeyEvent event) {
21442233
return true;
21452234
}
21462235

2236+
// 鼠标中键(同时影响触摸返回)
2237+
if (detectMouseMiddle && eventSource == InputDevice.SOURCE_KEYBOARD &&
2238+
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
2239+
if (android.os.SystemClock.uptimeMillis() - lastMouseHoverTime < 250) {
2240+
detectMouseMiddleDown = true;
2241+
detectMouseMiddle = false;
2242+
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_MIDDLE);
2243+
return true;
2244+
}
2245+
}
2246+
21472247
boolean handled = false;
21482248

21492249
if (ControllerHandler.isGameControllerDevice(event.getDevice())) {
@@ -2242,6 +2342,73 @@ public boolean handleKeyUp(KeyEvent event) {
22422342
}
22432343
}
22442344
}
2345+
2346+
int keyCode = event.getKeyCode();
2347+
pressedKeys.remove(keyCode);
2348+
2349+
if (prefConfig.enableCustomKeyMap) {
2350+
if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
2351+
handler.removeCallbacks(escConfirmRunnable); // 若未执行则移除
2352+
if (escState == 1) {
2353+
// 没有组合键,短时间内抬起
2354+
// Log.d("debug", "Esc: Up (no combo)");
2355+
short translated = keyboardTranslator.translate(KeyEvent.KEYCODE_ESCAPE, event.getDeviceId());
2356+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2357+
// 延迟发送 KEY_UP,不堵塞主线程
2358+
handler.postDelayed(() -> {
2359+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2360+
}, 50); // 延迟 50ms
2361+
escState = 0;
2362+
} else if (escState == 2) {
2363+
// 组合键已触发,不处理ESC
2364+
// Log.d("debug", "Esc: Up (combo)");
2365+
escState = 0;
2366+
}else{
2367+
// Log.d("debug", "Esc: Up (no custom combo)");
2368+
short translated = keyboardTranslator.translate(KeyEvent.KEYCODE_ESCAPE, event.getDeviceId());
2369+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2370+
escState = 0;
2371+
}
2372+
2373+
return true;
2374+
}
2375+
if(escState == 2){
2376+
if (keyCode == KeyEvent.KEYCODE_Q) {
2377+
// Log.d("debug", "Esc + Q: Up");
2378+
onBackPressed();
2379+
return true;
2380+
}
2381+
if (keyCode >= KeyEvent.KEYCODE_1 && keyCode <= KeyEvent.KEYCODE_9) {
2382+
// Log.d("debug", "Esc + num: Up");
2383+
int fKeyCode = KeyEvent.KEYCODE_F1 + (keyCode - KeyEvent.KEYCODE_1);
2384+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2385+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2386+
return true;
2387+
}
2388+
if (keyCode == KeyEvent.KEYCODE_0) {
2389+
// Log.d("debug", "Esc + 0: Up -> F10");
2390+
int fKeyCode = KeyEvent.KEYCODE_F10;
2391+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2392+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2393+
return true;
2394+
}
2395+
if (keyCode == KeyEvent.KEYCODE_MINUS) {
2396+
// Log.d("debug", "Esc + -: Up -> F11");
2397+
int fKeyCode = KeyEvent.KEYCODE_F11;
2398+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2399+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2400+
return true;
2401+
}
2402+
if (keyCode == KeyEvent.KEYCODE_EQUALS) {
2403+
// Log.d("debug", "Esc + =: Up -> F12");
2404+
int fKeyCode = KeyEvent.KEYCODE_F12;
2405+
short translated = keyboardTranslator.translate(fKeyCode, event.getDeviceId());
2406+
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, (byte) 0, MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
2407+
return true;
2408+
}
2409+
}
2410+
}
2411+
22452412
// Pass-through virtual navigation keys
22462413
if ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
22472414
return false;
@@ -2266,6 +2433,14 @@ public boolean handleKeyUp(KeyEvent event) {
22662433
return true;
22672434
}
22682435

2436+
// 鼠标中键(同时影响触摸返回)
2437+
if (detectMouseMiddleDown && eventSource == InputDevice.SOURCE_KEYBOARD &&
2438+
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
2439+
detectMouseMiddleDown = false;
2440+
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_MIDDLE);
2441+
return true;
2442+
}
2443+
22692444
boolean handled = false;
22702445
if (ControllerHandler.isGameControllerDevice(event.getDevice())) {
22712446
// Always try the controller handler first, unless it's an alphanumeric keyboard device.
@@ -2831,6 +3006,120 @@ private boolean handleMotionEvent(View view, MotionEvent event) {
28313006
}
28323007

28333008
int eventSource = event.getSource();
3009+
3010+
// 支持华为平板识别原生鼠标下的滚动逻辑:一次8194鼠标滑动+五次4098屏幕滑动
3011+
if (prefConfig.fixMouseWheel && cursorVisible &&
3012+
eventSource == InputDevice.SOURCE_MOUSE &&
3013+
(event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE ||
3014+
event.getActionMasked() == MotionEvent.ACTION_MOVE ||
3015+
event.getActionMasked() == MotionEvent.ACTION_DOWN ||
3016+
event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS)){
3017+
lastMouseHoverTime = android.os.SystemClock.uptimeMillis();
3018+
detectScrolling = true;
3019+
}
3020+
else if (detectScrolling){
3021+
// 拦截系统通过触摸屏(Source 4098)模拟的鼠标滚轮事件
3022+
if (eventSource == InputDevice.SOURCE_TOUCHSCREEN && event.getPointerCount() == 1) {
3023+
int action = event.getActionMasked();
3024+
if (action == MotionEvent.ACTION_CANCEL) {
3025+
waitRelease = true;
3026+
}
3027+
else if (action == MotionEvent.ACTION_DOWN) {
3028+
long currentTime = android.os.SystemClock.uptimeMillis();
3029+
long timeDiff = currentTime - lastMouseHoverTime;
3030+
if (timeDiff <= 40 || waitRelease){
3031+
fakeScrollInitialY = event.getY();
3032+
// 同步发送绝对坐标给远程
3033+
conn.sendMousePosition(
3034+
(short)event.getX(),
3035+
(short)event.getY(),
3036+
(short)streamView.getWidth(),
3037+
(short)streamView.getHeight()
3038+
);
3039+
return true;
3040+
}
3041+
else {
3042+
// Log.d("debug", "timeDiff: " + timeDiff);
3043+
detectScrolling = false;
3044+
waitRelease = false;
3045+
scrollTotal = 0;
3046+
}
3047+
}
3048+
else if (action == MotionEvent.ACTION_MOVE) {
3049+
float deltaY = event.getY() - fakeScrollInitialY;
3050+
// Log.d("debug", "deltaY: " + deltaY);
3051+
// 向上滑一次时deltaY=64,向下-64,滚动一格产生两次
3052+
fakeScrollInitialY = event.getY();
3053+
scrollTotal = scrollTotal + deltaY;
3054+
if (scrollTotal > 127.99){
3055+
scrollTotal = scrollTotal - 128;
3056+
// Log.d("debug", "send: up");
3057+
conn.sendMouseHighResScroll((short) 120);
3058+
}
3059+
else if (scrollTotal < -127.99){
3060+
scrollTotal = scrollTotal + 128;
3061+
// Log.d("debug", "send: down");
3062+
conn.sendMouseHighResScroll((short) -120);
3063+
}
3064+
3065+
// 拦截事件,不再向下传递,避免触发点击或UI滑动
3066+
return true;
3067+
}
3068+
else if (action == MotionEvent.ACTION_UP) {
3069+
// Log.d("debug", "scrollTotal: " + scrollTotal);
3070+
while(scrollTotal > 127.99 || scrollTotal < -127.99) {
3071+
// Log.d("debug", "滚轮还未发完");
3072+
if (scrollTotal > 127.99){
3073+
scrollTotal = scrollTotal - 128;
3074+
// Log.d("debug", "send: up");
3075+
conn.sendMouseHighResScroll((short) 120);
3076+
}
3077+
else {
3078+
scrollTotal = scrollTotal + 128;
3079+
// Log.d("debug", "send: down");
3080+
conn.sendMouseHighResScroll((short) -120);
3081+
}
3082+
}
3083+
if (!waitRelease) {
3084+
detectScrolling = false;
3085+
}
3086+
fakeScrollInitialY = -1;
3087+
scrollTotal = 0;
3088+
return true;
3089+
}
3090+
else {
3091+
detectScrolling = false;
3092+
waitRelease = false;
3093+
scrollTotal = 0;
3094+
}
3095+
}
3096+
else if (waitRelease && eventSource == InputDevice.SOURCE_MOUSE && event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE) {
3097+
waitRelease = false;
3098+
}
3099+
else if (!waitRelease){
3100+
detectScrolling = false;
3101+
scrollTotal = 0;
3102+
}
3103+
}
3104+
3105+
// 支持华为鼠标中键
3106+
if (prefConfig.fixMouseMiddle) {
3107+
if (cursorVisible) {
3108+
// 本地模式:8194:7+7(x和y不变)
3109+
if (eventSource == InputDevice.SOURCE_MOUSE &&
3110+
event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
3111+
lastMouseHoverTime = android.os.SystemClock.uptimeMillis();
3112+
detectMouseMiddle = true;
3113+
}
3114+
}
3115+
else if (eventSource == InputDevice.SOURCE_MOUSE_RELATIVE &&
3116+
event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE) {
3117+
// 远程模式:131076:2+11+12+2(x和y全0.0,中间可能夹杂2,依靠12来检测)
3118+
lastMouseHoverTime = android.os.SystemClock.uptimeMillis();
3119+
detectMouseMiddle = true;
3120+
}
3121+
}
3122+
28343123
int deviceSources = event.getDevice() != null ? event.getDevice().getSources() : 0;
28353124

28363125
// 本地鼠标指针模式的特殊处理

app/src/main/java/com/limelight/PcView.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.limelight.preferences.GlPreferences;
3333
import com.limelight.preferences.PreferenceConfiguration;
3434
import com.limelight.preferences.StreamSettings;
35+
import com.limelight.services.KeyboardAccessibilityService;
3536
import com.limelight.ui.AdapterFragment;
3637
import com.limelight.ui.AdapterFragmentCallbacks;
3738
import com.limelight.utils.AnalyticsManager;
@@ -196,6 +197,28 @@ public void onServiceDisconnected(ComponentName className) {
196197
protected void onCreate(Bundle savedInstanceState) {
197198
super.onCreate(savedInstanceState);
198199

200+
//自动获取无障碍权限
201+
try {
202+
ComponentName cn = new ComponentName(this, KeyboardAccessibilityService.class);
203+
String myService = cn.flattenToString();
204+
String enabledServices = Settings.Secure.getString(getContentResolver(),
205+
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
206+
207+
if (enabledServices == null || !enabledServices.contains(myService)) {
208+
if (enabledServices == null || enabledServices.isEmpty()) {
209+
enabledServices = myService;
210+
} else {
211+
enabledServices += ":" + myService;
212+
}
213+
214+
// 这里可能会抛异常
215+
Settings.Secure.putString(getContentResolver(),
216+
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
217+
}
218+
} catch (SecurityException e) {
219+
// 没无障碍权限
220+
}
221+
199222
easyTierController = new EasyTierController(this, this);
200223
inForeground = true;
201224
initBitmapCache();

0 commit comments

Comments
 (0)