fix: android, touch mode, soft keyboard, no pointer events (#8409)

* fix: android, touch mode, soft keyboard, no pointer events

Signed-off-by: fufesou <linlong1266@gmail.com>

* Reset lastIsBlocked on touch mode toggled

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: reset lastIsBlocked when updating keyHelpToolsRect

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2024-06-19 15:58:23 +08:00 committed by GitHub
parent 60dc40f47f
commit e50b72622c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 88 additions and 5 deletions

View File

@ -95,8 +95,9 @@ class _RawTouchGestureDetectorRegionState
}
if (handleTouch) {
// Desktop or mobile "Touch mode"
ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
inputModel.tapDown(MouseButtons.left);
if (ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy)) {
inputModel.tapDown(MouseButtons.left);
}
}
}
@ -105,8 +106,9 @@ class _RawTouchGestureDetectorRegionState
return;
}
if (handleTouch) {
ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
inputModel.tapUp(MouseButtons.left);
if (ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy)) {
inputModel.tapUp(MouseButtons.left);
}
}
}
@ -134,6 +136,9 @@ class _RawTouchGestureDetectorRegionState
if (lastDeviceKind != PointerDeviceKind.touch) {
return;
}
if (ffiModel.touchMode && ffi.cursorModel.lastIsBlocked) {
return;
}
inputModel.tap(MouseButtons.left);
inputModel.tap(MouseButtons.left);
}
@ -222,6 +227,9 @@ class _RawTouchGestureDetectorRegionState
return;
}
if (handleTouch) {
if (ffi.cursorModel.shouldBlock(d.localPosition.dx, d.localPosition.dy)) {
return;
}
if (isDesktop) {
ffi.cursorModel.trySetRemoteWindowCoords();
}
@ -244,6 +252,9 @@ class _RawTouchGestureDetectorRegionState
if (lastDeviceKind != PointerDeviceKind.touch) {
return;
}
if (ffi.cursorModel.shouldBlock(d.localPosition.dx, d.localPosition.dy)) {
return;
}
ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch);
}

View File

@ -679,6 +679,7 @@ class _KeyHelpToolsState extends State<KeyHelpTools> {
var _fn = false;
var _pin = false;
final _keyboardVisibilityController = KeyboardVisibilityController();
final _key = GlobalKey();
InputModel get inputModel => gFFI.inputModel;
@ -703,6 +704,24 @@ class _KeyHelpToolsState extends State<KeyHelpTools> {
onPressed: onPressed);
}
@override
void initState() {
super.initState();
}
_updateRect() {
RenderObject? renderObject = _key.currentContext?.findRenderObject();
if (renderObject == null) {
return;
}
if (renderObject is RenderBox) {
final size = renderObject.size;
Offset pos = renderObject.localToGlobal(Offset.zero);
gFFI.cursorModel.keyHelpToolsRect =
Rect.fromLTWH(pos.dx, pos.dy, size.width, size.height);
}
}
@override
Widget build(BuildContext context) {
final hasModifierOn = inputModel.ctrl ||
@ -711,6 +730,7 @@ class _KeyHelpToolsState extends State<KeyHelpTools> {
inputModel.command;
if (!_pin && !hasModifierOn && !widget.requestShow) {
gFFI.cursorModel.keyHelpToolsRect = null;
return Offstage();
}
final size = MediaQuery.of(context).size;
@ -821,7 +841,12 @@ class _KeyHelpToolsState extends State<KeyHelpTools> {
}),
];
final space = size.width > 320 ? 4.0 : 2.0;
// 500 ms is long enough for this widget to be built!
Future.delayed(Duration(milliseconds: 500), () {
_updateRect();
});
return Container(
key: _key,
color: Color(0xAA000000),
padding: EdgeInsets.only(
top: _keyboardVisibilityController.isVisible ? 24 : 4, bottom: 8),

View File

@ -1800,6 +1800,32 @@ class CursorModel with ChangeNotifier {
String peerId = '';
WeakReference<FFI> parent;
// Only for mobile, touch mode
// To block touch event above the KeyHelpTools
//
// A better way is to not listen events from the KeyHelpTools.
// But we're now using a Container(child: Stack(...)) to wrap the KeyHelpTools,
// and the listener is on the Container.
Rect? _keyHelpToolsRect;
bool _lastIsBlocked = false;
set keyHelpToolsRect(Rect? r) {
_keyHelpToolsRect = r;
if (r == null) {
_lastIsBlocked = false;
} else {
// `lastIsBlocked` is only used in common/widgets/remote_input.dart -> _RawTouchGestureDetectorRegionState -> onDoubleTap()
// Because onDoubleTap() doesn't have the `event` parameter, we can't get the touch event's position.
//
// Block the touch event is safe here.
// `lastIsBlocked` is only used in onDoubleTap() to block the touch event from the KeyHelpTools.
// `lastIsBlocked` will be set when the cursor is moving or touch somewhere else.
_lastIsBlocked = true;
}
}
get lastIsBlocked => _lastIsBlocked;
ui.Image? get image => _image;
CursorData? get cache => _cache;
@ -1844,9 +1870,10 @@ class CursorModel with ChangeNotifier {
return Rect.fromLTWH(x0, y0, size.width / scale, size.height / scale);
}
get keyboardHeight => MediaQueryData.fromWindow(ui.window).viewInsets.bottom;
double adjustForKeyboard() {
final m = MediaQueryData.fromWindow(ui.window);
var keyboardHeight = m.viewInsets.bottom;
final size = m.size;
if (keyboardHeight < 100) return 0;
final s = parent.target?.canvasModel.scale ?? 1.0;
@ -1855,9 +1882,29 @@ class CursorModel with ChangeNotifier {
return h - thresh;
}
// mobile Soft keyboard, block touch event from the KeyHelpTools
shouldBlock(double x, double y) {
if (!(parent.target?.ffiModel.touchMode ?? false)) {
return false;
}
if (_keyHelpToolsRect == null) {
return false;
}
if (isPointInRect(Offset(x, y), _keyHelpToolsRect!)) {
return true;
}
return false;
}
move(double x, double y) {
if (shouldBlock(x, y)) {
_lastIsBlocked = true;
return false;
}
_lastIsBlocked = false;
moveLocal(x, y);
parent.target?.inputModel.moveMouse(_x, _y);
return true;
}
moveLocal(double x, double y) {