feat(remote): 修复键盘输入映射并重构连接流程

- Android端注入按键时显式设置SOURCE_KEYBOARD,修复IME丢弃事件导致输入框无法输入文字的问题
- Flutter端新增Flutter逻辑键到Android keyCode的转换映射,避免功能键误触发
- 重构RemoteController,分离信令连接与远程控制逻辑,支持设备列表选择与配对码兑换
- AuthRepository接口新增getBindings、getOnlineDevices、redeemPairingCode方法
- DioAuthRepository实现401自动刷新token重试机制
- ConnectionSessionState扩展设备列表、在线状态、配对码等状态字段
This commit is contained in:
TongTongStudio
2026-08-03 20:22:29 +08:00
parent 79cffcb041
commit e1de4c8170
21 changed files with 1529 additions and 703 deletions

View File

@@ -4,6 +4,8 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webrtc_controller_flutter/core/utils/control_commands.dart';
/// 远端触摸控制层(对应 Android 端 RemoteTouchView
///
/// 捕获指针(触摸/鼠标)事件,将其转换为相对于控件区域的百分比坐标
@@ -43,6 +45,10 @@ class RemoteTouchView extends StatefulWidget {
}
class _RemoteTouchViewState extends State<RemoteTouchView> {
/// 用于捕获物理键盘事件的焦点节点。
/// 设置 [FocusNode.skipTraversal] 避免桌面端获得焦点时绘制一圈绿色高亮边框。
final FocusNode _focusNode = FocusNode(skipTraversal: true);
Offset? _startPosition;
Offset? _currentPosition;
DateTime? _startTime;
@@ -77,19 +83,41 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
@override
void dispose() {
_cancelLongPress();
_focusNode.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
// 关闭框架的焦点高亮描边:本控件需要 autofocus 捕获物理键盘,但框架在
// 检测到键盘交互(传统高亮模式)后会给焦点节点绘制一圈绿色高亮边框。
// 将高亮策略设为 alwaysTouch 后边框不再绘制,键盘事件捕获不受影响。
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch;
}
@override
Widget build(BuildContext context) {
return Focus(
autofocus: true,
onKeyEvent: (node, event) {
return Theme(
data: Theme.of(context).copyWith(
focusColor: Colors.transparent,
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
hoverColor: Colors.transparent,
),
child: Focus(
autofocus: true,
focusNode: _focusNode,
onKeyEvent: (node, event) {
// 必须将 Flutter 的逻辑键转换为 Android keyCode 再下发,否则会被控端
// 误识别为功能键/组合键(屏幕乱跳、输入框无法输入文字)。
final int androidKeyCode = ControlCommands.toAndroidKeyCode(event.logicalKey);
if (androidKeyCode == 0) return KeyEventResult.ignored;
if (event is KeyDownEvent) {
widget.onKey(event.logicalKey.keyId, 0);
widget.onKey(androidKeyCode, 0);
return KeyEventResult.handled;
} else if (event is KeyUpEvent) {
widget.onKey(event.logicalKey.keyId, 1);
widget.onKey(androidKeyCode, 1);
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
@@ -177,6 +205,7 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
child: SizedBox.expand(),
),
),
);
}
),
);
}
}