feat: 支持按键分离事件与键盘捕获,并优化UI

- 后端与前端新增 keyAction 参数,支持按键按下/抬起独立事件,保持向下兼容
- 前端控制栏支持 pointerdown/pointerup 长按,新增键盘捕获输入框,映射浏览器按键到 Android KeyEvent
- 重构顶栏布局:用户区右置并添加在线指示器、状态文本省略,优化窄屏响应式表现
- 控制栏录制按钮组防拆行,分辨率/帧率选择器自适应收缩,全局样式增强
- 修复 AdminAuthFilter 中 doFilter 被异常捕获导致误返回 401 的问题
- 移除管理后台中用户 admin 角色及相关 UI 与 API
- 更新信令前端环境代理地址,修正路由名称大小写
This commit is contained in:
2026-08-03 11:09:37 +08:00
parent e6ed7c8e3e
commit 78aa3d3c71
16 changed files with 374 additions and 79 deletions

View File

@@ -53,7 +53,7 @@ public class AccessibilityInputUtils implements InputExecutor {
}
@Override
public void injectKeyEvent(int keyCode) {
public void injectKeyEvent(int keyCode, int keyAction) {
KeyboardAccessibilityService svc = getService();
if (svc == null) {
Log.w(TAG, "Accessibility service not running, cannot inject key");

View File

@@ -133,8 +133,13 @@ public class InputCommandHandler {
private void handleKey(ControlMessage command) {
int keyCode = command.getKeyCode();
Log.d(TAG, "Key press: " + keyCode);
inputExecutor.injectKeyEvent(keyCode);
if (keyCode == 0) {
Log.w(TAG, "Ignoring KEY command with keyCode=0");
return;
}
int keyAction = command.getKeyAction();
Log.d(TAG, "Key press: keyCode=" + keyCode + ", keyAction=" + keyAction);
inputExecutor.injectKeyEvent(keyCode, keyAction);
}
private void handleSwipe(ControlMessage command) {

View File

@@ -7,7 +7,12 @@ public interface InputExecutor {
void injectTap(int x, int y);
void injectLongPress(int x, int y);
void injectSwipe(int x1, int y1, int x2, int y2, long duration);
void injectKeyEvent(int keyCode);
/**
* 注入按键事件。
* @param keyCode Android KeyEvent 键值(如 KeyEvent.KEYCODE_A
* @param keyAction 动作0=ACTION_DOWN1=ACTION_UP传 -1 表示“按下并立即抬起”的一次性点击(兼容旧行为)。
*/
void injectKeyEvent(int keyCode, int keyAction);
void injectMotionEvent(int action, int x, int y);
/**

View File

@@ -31,7 +31,7 @@ public class RootShellInputUtils implements InputExecutor {
}
@Override
public void injectKeyEvent(int keyCode) {
public void injectKeyEvent(int keyCode, int keyAction) {
executeRootCommand(String.format(Locale.US, "input keyevent %d", keyCode));
}

View File

@@ -25,7 +25,7 @@ public class ShellInputUtils implements InputExecutor {
}
@Override
public void injectKeyEvent(int keyCode) {
public void injectKeyEvent(int keyCode, int keyAction) {
executeShellCommand(String.format(Locale.US, "input keyevent %d", keyCode));
}

View File

@@ -2,6 +2,7 @@ package com.ttstd.controlled.input;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseLongArray;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
@@ -21,6 +22,7 @@ public class SystemInputUtils implements InputExecutor {
private static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0;
private static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
private long mDownTime;
private final SparseLongArray mKeyDownTimes = new SparseLongArray();
public SystemInputUtils() {
try {
@@ -69,10 +71,28 @@ public class SystemInputUtils implements InputExecutor {
}
@Override
public void injectKeyEvent(int keyCode) {
public void injectKeyEvent(int keyCode, int keyAction) {
if (mInputManager == null || mInjectInputEventMethod == null) {
return;
}
long now = SystemClock.uptimeMillis();
injectKeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode);
injectKeyEvent(now, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keyCode);
if (keyAction < 0) {
// 向后兼容:未指定动作时执行“按下并立即抬起”的一次性点击
injectKeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode);
injectKeyEvent(now, now, KeyEvent.ACTION_UP, keyCode);
return;
}
int action = (keyAction == 0) ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
long downTime;
if (action == KeyEvent.ACTION_DOWN) {
downTime = now;
mKeyDownTimes.put(keyCode, downTime);
} else {
// 抬起时复用按下时刻,保证同一次按键周期内 downTime 一致(用于长按/组合键识别)
downTime = mKeyDownTimes.get(keyCode, now);
mKeyDownTimes.delete(keyCode);
}
injectKeyEvent(downTime, now, action, keyCode);
}
@Override