102102import java .security .cert .CertificateFactory ;
103103import java .security .cert .X509Certificate ;
104104import java .util .ArrayList ;
105+ import java .util .HashSet ;
105106import java .util .List ;
106107import java .util .HashMap ;
107108import java .util .Map ;
108109import java .util .Locale ;
110+ import java .util .Set ;
109111
110112import 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 // 本地鼠标指针模式的特殊处理
0 commit comments