Merge pull request from fufesou/fix/cursor_hotxy_mismatch

fix, cursor (hotx,hoty) mismatch sometimes
This commit is contained in:
RustDesk 2023-10-03 23:37:45 +08:00 committed by GitHub
commit a723518346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 37 deletions
flutter/lib
desktop/pages
models

@ -614,7 +614,7 @@ class _ImagePaintState extends State<ImagePaint> {
} else { } else {
final key = cache.updateGetKey(scale); final key = cache.updateGetKey(scale);
if (!cursor.cachedKeys.contains(key)) { if (!cursor.cachedKeys.contains(key)) {
debugPrint("Register custom cursor with key $key"); debugPrint("Register custom cursor with key $key (${cache.hotx},${cache.hoty})");
// [Safety] // [Safety]
// It's ok to call async registerCursor in current synchronous context, // It's ok to call async registerCursor in current synchronous context,
// because activating the cursor is also an async call and will always // because activating the cursor is also an async call and will always

@ -203,10 +203,12 @@ class FfiModel with ChangeNotifier {
updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId); updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId);
setConnectionType(peerId, data.secure, data.direct); setConnectionType(peerId, data.secure, data.direct);
await handlePeerInfo(data.peerInfo, peerId); await handlePeerInfo(data.peerInfo, peerId);
for (var element in data.cursorDataList) { for (final element in data.cursorDataList) {
updateLastCursorId(element);
await handleCursorData(element); await handleCursorData(element);
} }
await handleCursorId(data.lastCursorId); updateLastCursorId(data.lastCursorId);
handleCursorId(data.lastCursorId);
} }
// todo: why called by two position // todo: why called by two position
@ -225,9 +227,11 @@ class FfiModel with ChangeNotifier {
} else if (name == 'switch_display') { } else if (name == 'switch_display') {
handleSwitchDisplay(evt, sessionId, peerId); handleSwitchDisplay(evt, sessionId, peerId);
} else if (name == 'cursor_data') { } else if (name == 'cursor_data') {
updateLastCursorId(evt);
await handleCursorData(evt); await handleCursorData(evt);
} else if (name == 'cursor_id') { } else if (name == 'cursor_id') {
await handleCursorId(evt); updateLastCursorId(evt);
handleCursorId(evt);
} else if (name == 'cursor_position') { } else if (name == 'cursor_position') {
await parent.target?.cursorModel.updateCursorPosition(evt, peerId); await parent.target?.cursorModel.updateCursorPosition(evt, peerId);
} else if (name == 'clipboard') { } else if (name == 'clipboard') {
@ -651,9 +655,13 @@ class FfiModel with ChangeNotifier {
return d; return d;
} }
handleCursorId(Map<String, dynamic> evt) async { updateLastCursorId(Map<String, dynamic> evt) {
parent.target?.cursorModel.id = int.parse(evt['id']);
}
handleCursorId(Map<String, dynamic> evt) {
cachedPeerData.lastCursorId = evt; cachedPeerData.lastCursorId = evt;
await parent.target?.cursorModel.updateCursorId(evt); parent.target?.cursorModel.updateCursorId(evt);
} }
handleCursorData(Map<String, dynamic> evt) async { handleCursorData(Map<String, dynamic> evt) async {
@ -1279,6 +1287,7 @@ class CursorModel with ChangeNotifier {
final _cacheKeys = <String>{}; final _cacheKeys = <String>{};
double _x = -10000; double _x = -10000;
double _y = -10000; double _y = -10000;
int _id = -1;
double _hotx = 0; double _hotx = 0;
double _hoty = 0; double _hoty = 0;
double _displayOriginX = 0; double _displayOriginX = 0;
@ -1287,7 +1296,7 @@ class CursorModel with ChangeNotifier {
bool gotMouseControl = true; bool gotMouseControl = true;
DateTime _lastPeerMouse = DateTime.now() DateTime _lastPeerMouse = DateTime.now()
.subtract(Duration(milliseconds: 3000 * kMouseControlTimeoutMSec)); .subtract(Duration(milliseconds: 3000 * kMouseControlTimeoutMSec));
String id = ''; String peerId = '';
WeakReference<FFI> parent; WeakReference<FFI> parent;
ui.Image? get image => _image; ui.Image? get image => _image;
@ -1301,6 +1310,8 @@ class CursorModel with ChangeNotifier {
double get hotx => _hotx; double get hotx => _hotx;
double get hoty => _hoty; double get hoty => _hoty;
set id(int id) => _id = id;
bool get isPeerControlProtected => bool get isPeerControlProtected =>
DateTime.now().difference(_lastPeerMouse).inMilliseconds < DateTime.now().difference(_lastPeerMouse).inMilliseconds <
kMouseControlTimeoutMSec; kMouseControlTimeoutMSec;
@ -1439,32 +1450,33 @@ class CursorModel with ChangeNotifier {
} }
updateCursorData(Map<String, dynamic> evt) async { updateCursorData(Map<String, dynamic> evt) async {
var id = int.parse(evt['id']); final id = int.parse(evt['id']);
_hotx = double.parse(evt['hotx']); final hotx = double.parse(evt['hotx']);
_hoty = double.parse(evt['hoty']); final hoty = double.parse(evt['hoty']);
var width = int.parse(evt['width']); final width = int.parse(evt['width']);
var height = int.parse(evt['height']); final height = int.parse(evt['height']);
List<dynamic> colors = json.decode(evt['colors']); List<dynamic> colors = json.decode(evt['colors']);
final rgba = Uint8List.fromList(colors.map((s) => s as int).toList()); final rgba = Uint8List.fromList(colors.map((s) => s as int).toList());
final image = await img.decodeImageFromPixels( final image = await img.decodeImageFromPixels(
rgba, width, height, ui.PixelFormat.rgba8888); rgba, width, height, ui.PixelFormat.rgba8888);
_image = image; if (await _updateCache(rgba, image, id, hotx, hoty, width, height)) {
if (await _updateCache(rgba, image, id, width, height)) { _images[id] = Tuple3(image, hotx, hoty);
_images[id] = Tuple3(image, _hotx, _hoty);
} else {
_hotx = 0;
_hoty = 0;
}
try {
// my throw exception, because the listener maybe already dispose
notifyListeners();
} catch (e) {
debugPrint('WARNING: updateCursorId $id, without notifyListeners(). $e');
} }
// Update last cursor data.
// Do not use the previous `image` and `id`, because `_id` may be changed.
_updateCurData();
} }
Future<bool> _updateCache( Future<bool> _updateCache(
Uint8List rgba, ui.Image image, int id, int w, int h) async { Uint8List rgba,
ui.Image image,
int id,
double hotx,
double hoty,
int w,
int h,
) async {
Uint8List? data; Uint8List? data;
img2.Image imgOrigin = img2.Image.fromBytes( img2.Image imgOrigin = img2.Image.fromBytes(
width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
@ -1478,33 +1490,45 @@ class CursorModel with ChangeNotifier {
} }
data = imgBytes.buffer.asUint8List(); data = imgBytes.buffer.asUint8List();
} }
_cache = CursorData( final cache = CursorData(
peerId: this.id, peerId: peerId,
id: id, id: id,
image: imgOrigin, image: imgOrigin,
scale: 1.0, scale: 1.0,
data: data, data: data,
hotxOrigin: _hotx, hotxOrigin: hotx,
hotyOrigin: _hoty, hotyOrigin: hoty,
width: w, width: w,
height: h, height: h,
); );
_cacheMap[id] = _cache!; _cacheMap[id] = cache;
return true; return true;
} }
updateCursorId(Map<String, dynamic> evt) async { bool _updateCurData() {
final id = int.parse(evt['id']); _cache = _cacheMap[_id];
_cache = _cacheMap[id]; final tmp = _images[_id];
final tmp = _images[id];
if (tmp != null) { if (tmp != null) {
_image = tmp.item1; _image = tmp.item1;
_hotx = tmp.item2; _hotx = tmp.item2;
_hoty = tmp.item3; _hoty = tmp.item3;
try {
// may throw exception, because the listener maybe already dispose
notifyListeners(); notifyListeners();
} else { } catch (e) {
debugPrint( debugPrint(
'WARNING: updateCursorId $id, cache is ${_cache == null ? "null" : "not null"}. without notifyListeners()'); 'WARNING: updateCursorId $_id, without notifyListeners(). $e');
}
return true;
} else {
return false;
}
}
updateCursorId(Map<String, dynamic> evt) {
if (!_updateCurData()) {
debugPrint(
'WARNING: updateCursorId $_id, cache is ${_cache == null ? "null" : "not null"}. without notifyListeners()');
} }
} }
@ -1748,7 +1772,7 @@ class FFI {
connType = ConnType.defaultConn; connType = ConnType.defaultConn;
canvasModel.id = id; canvasModel.id = id;
imageModel.id = id; imageModel.id = id;
cursorModel.id = id; cursorModel.peerId = id;
} }
// If tabWindowId != null, this session is a "tab -> window" one. // If tabWindowId != null, this session is a "tab -> window" one.
// Else this session is a new one. // Else this session is a new one.